Move compiler scripting tests to scripting plugin, remove unused funs

also remove some tests that are covered in the scripting-compiler
tests now.
Part of the cleanup to rewrite scripting to the new infrastructure.
This commit is contained in:
Ilya Chernikov
2020-04-03 23:02:40 +02:00
parent cf387ffad1
commit d863dc04e6
49 changed files with 334 additions and 279 deletions
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDe
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
import org.jetbrains.kotlin.backend.jvm.jvmPhases
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
@@ -76,9 +75,7 @@ import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
import org.jetbrains.kotlin.utils.tryConstructClassFromStringArgs
import java.io.File
import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader
object KotlinToJVMBytecodeCompiler {
@@ -443,26 +440,6 @@ object KotlinToJVMBytecodeCompiler {
}
}
fun compileAndExecuteScript(environment: KotlinCoreEnvironment, scriptArgs: List<String>): ExitCode {
val scriptClass = compileScript(environment) ?: return ExitCode.COMPILATION_ERROR
try {
try {
tryConstructClassFromStringArgs(scriptClass, scriptArgs)
?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n")
} finally {
// NB: these lines are required (see KT-9546) but aren't covered by tests
System.out.flush()
System.err.flush()
}
} catch (e: Throwable) {
reportExceptionFromScript(e)
return ExitCode.SCRIPT_EXECUTION_ERROR
}
return ExitCode.OK
}
private fun repeatAnalysisIfNeeded(
result: AnalysisResult?,
environment: KotlinCoreEnvironment,
@@ -496,42 +473,6 @@ object KotlinToJVMBytecodeCompiler {
return result
}
private fun reportExceptionFromScript(exception: Throwable) {
// expecting InvocationTargetException from constructor invocation with cause that describes the actual cause
val stream = System.err
val cause = exception.cause
if (exception !is InvocationTargetException || cause == null) {
exception.printStackTrace(stream)
return
}
stream.println(cause)
val fullTrace = cause.stackTrace
for (i in 0 until fullTrace.size - exception.stackTrace.size) {
stream.println("\tat " + fullTrace[i])
}
}
fun compileScript(environment: KotlinCoreEnvironment, parentClassLoader: ClassLoader? = null): Class<*>? {
val state = analyzeAndGenerate(environment) ?: return null
try {
val urls = environment.configuration.getList(CLIConfigurationKeys.CONTENT_ROOTS).mapNotNull { root ->
when (root) {
is JvmModulePathRoot -> root.file // TODO: only add required modules
is JvmClasspathRoot -> root.file
else -> null
}
}.map { it.toURI().toURL() }
val classLoader = GeneratedClassLoader(state.factory, parentClassLoader ?: URLClassLoader(urls.toTypedArray(), null))
val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed")
return classLoader.loadClass(script.fqName.asString())
} catch (e: Exception) {
throw RuntimeException("Failed to evaluate script: $e", e)
}
}
@Suppress("MemberVisibilityCanBePrivate") // Used in ExecuteKotlinScriptMojo
fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? {
val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.script.loadScriptingPlugin
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.scripts.TestKotlinScriptDependenciesResolver
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
@@ -145,8 +144,5 @@ class ScriptGenTest : CodegenTestCase() {
}
@Suppress("unused")
@ScriptTemplateDefinition(
scriptFilePattern = ".*\\.lang\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
)
@ScriptTemplateDefinition(scriptFilePattern = ".*\\.lang\\.kts")
abstract class ScriptWithIntParam(val num: Int)
@@ -28,11 +28,12 @@ import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets
import org.jetbrains.kotlin.daemon.client.KotlinCompilerClient
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase
import org.jetbrains.kotlin.scripts.captureOut
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.resetApplicationToNull
import org.junit.Assert
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.net.URLClassLoader
class CompilerApiTest : KotlinIntegrationTestBase() {
@@ -204,3 +205,16 @@ fun TestMessageCollector.assertHasMessage(msg: String, desiredSeverity: Compiler
}
}
internal fun captureOut(body: () -> Unit): String {
val outStream = ByteArrayOutputStream()
val prevOut = System.out
System.setOut(PrintStream(outStream))
try {
body()
} finally {
System.out.flush()
System.setOut(prevOut)
}
return outStream.toString()
}
@@ -14,13 +14,13 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.captureOut
import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets
import org.jetbrains.kotlin.daemon.client.KotlinCompilerDaemonClient
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.ReportSeverity
import org.jetbrains.kotlin.daemon.loggerCompatiblePath
import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase
import org.jetbrains.kotlin.scripts.captureOut
import org.jetbrains.kotlin.test.IgnoreAll
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.resetApplicationToNull
@@ -1,56 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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.jetbrains.kotlin.scripts
import org.junit.Assert
import java.io.ByteArrayOutputStream
import java.io.PrintStream
internal const val NUM_4_LINE = "num: 4"
internal const val FIB_SCRIPT_OUTPUT_TAIL =
"""
fib(1)=1
fib(0)=1
fib(2)=2
fib(1)=1
fib(3)=3
fib(1)=1
fib(0)=1
fib(2)=2
fib(4)=5
"""
internal fun captureOut(body: () -> Unit): String {
val outStream = ByteArrayOutputStream()
val prevOut = System.out
System.setOut(PrintStream(outStream))
try {
body()
}
finally {
System.out.flush()
System.setOut(prevOut)
}
return outStream.toString()
}
private fun String.linesSplitTrim() =
split('\n','\r').map(String::trim).filter(String::isNotBlank)
internal fun assertEqualsTrimmed(expected: String, actual: String) =
Assert.assertEquals(expected.linesSplitTrim(), actual.linesSplitTrim())
@@ -17,12 +17,12 @@
package org.jetbrains.kotlin.script.util
import com.intellij.openapi.util.Disposer
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
@@ -35,9 +35,12 @@ import org.jetbrains.kotlin.script.util.templates.BindingsScriptTemplateWithLoca
import org.jetbrains.kotlin.script.util.templates.StandardArgsScriptTemplateWithLocalResolving
import org.jetbrains.kotlin.script.util.templates.StandardArgsScriptTemplateWithMavenResolving
import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerFromEnvironment
import org.jetbrains.kotlin.scripting.compiler.plugin.toCompilerMessageSeverity
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.utils.PathUtil.getResourcePathForClass
@@ -45,9 +48,13 @@ import org.junit.Assert
import org.junit.Ignore
import org.junit.Test
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.OutputStream
import java.io.PrintStream
import kotlin.reflect.KClass
import kotlin.script.experimental.api.onSuccess
import kotlin.script.experimental.api.valueOr
import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
const val KOTLIN_JAVA_RUNTIME_JAR = "kotlin-stdlib.jar"
@@ -180,8 +187,22 @@ done
}
messageCollector.report(CompilerMessageSeverity.LOGGING, "compilation classpath:\n ${environment.configuration.jvmClasspathRoots.joinToString("\n ")}")
val scriptCompiler = ScriptJvmCompilerFromEnvironment(environment)
return try {
KotlinToJVMBytecodeCompiler.compileScript(environment)
val script = File(scriptPath).toScriptSource()
val newScriptDefinition = ScriptDefinitionProvider.getInstance(environment.project)!!.findDefinition(script)!!
val compiledScript = scriptCompiler.compile(script, newScriptDefinition.compilationConfiguration).onSuccess {
runBlocking {
it.getClass(newScriptDefinition.evaluationConfiguration)
}
}.valueOr {
for (report in it.reports) {
messageCollector.report(report.severity.toCompilerMessageSeverity(), report.render(withSeverity = false))
}
return null
}
compiledScript.java
} catch (e: CompilationException) {
messageCollector.report(
CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e),
@@ -7,6 +7,8 @@ plugins {
}
dependencies {
testRuntimeOnly(intellijDep()) // Should come before compiler, because of "progarded" stuff needed for tests
compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:frontend.java"))
compileOnly(project(":compiler:psi"))
@@ -32,8 +34,7 @@ dependencies {
testCompile(projectTests(":compiler:tests-common"))
testCompile(commonDep("junit:junit"))
testRuntimeOnly(intellijCoreDep()) { includeJars("intellij-core") }
testRuntimeOnly(intellijDep()) { includeJars("jps-model") }
testImplementation(intellijCoreDep()) { includeJars("intellij-core") }
}
sourceSets {
@@ -60,4 +61,5 @@ testsJar()
projectTest {
dependsOn(":dist")
workingDir = rootDir
systemProperty("kotlin.test.script.classpath", testSourceSet.output.classesDirs.joinToString(File.pathSeparator))
}
@@ -141,7 +141,7 @@ abstract class AbstractScriptEvaluationExtension : ScriptEvaluationExtension {
}
}
private fun ScriptDiagnostic.Severity.toCompilerMessageSeverity(): CompilerMessageSeverity =
fun ScriptDiagnostic.Severity.toCompilerMessageSeverity(): CompilerMessageSeverity =
when (this) {
ScriptDiagnostic.Severity.FATAL -> CompilerMessageSeverity.EXCEPTION
ScriptDiagnostic.Severity.ERROR -> CompilerMessageSeverity.ERROR
@@ -1,5 +1,5 @@
import org.jetbrains.kotlin.scripts.*
import org.jetbrains.kotlin.scripting.compiler.test.*
// this script expected parameter num : Int
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.scripting.compiler.plugin
import junit.framework.Assert
import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
import org.junit.Assert
import org.junit.Test
import java.io.File
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.scripting.compiler.plugin
import com.intellij.openapi.Disposable
import com.intellij.openapi.util.Disposer
import junit.framework.Assert
import org.jetbrains.kotlin.cli.common.CLITool
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.junit.Assert
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.InputStream
@@ -1,9 +1,9 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.scripts
package org.jetbrains.kotlin.scripting.compiler.test
import junit.framework.TestCase
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
@@ -21,7 +21,7 @@ import java.io.File
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
private const val testDataPath = "compiler/testData/script/collectDependencies"
private const val testDataPath = "plugins/scripting/scripting-compiler/testData/compiler/collectDependencies"
class CollectScriptCompilationDependenciesTest : KtUsefulTestCase() {
@@ -1,19 +1,17 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.scripts
package org.jetbrains.kotlin.scripting.compiler.test
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.daemon.TestMessageCollector
import org.jetbrains.kotlin.script.loadScriptingPlugin
import org.jetbrains.kotlin.scripting.compiler.plugin.TestMessageCollector
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.test.ConfigurationKind
@@ -26,13 +24,10 @@ import java.io.File
import kotlin.reflect.KClass
import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.FileBasedScriptSource
import kotlin.script.experimental.host.FileScriptSource
import kotlin.script.experimental.host.ScriptingHostConfiguration
import kotlin.script.experimental.host.configurationDependencies
import kotlin.script.experimental.host.*
import kotlin.script.experimental.jvm.*
private const val testDataPath = "compiler/testData/script/cliCompilation"
private const val testDataPath = "plugins/scripting/scripting-compiler/testData/cliCompilation"
class ScriptCliCompilationTest : KtUsefulTestCase() {
@@ -69,7 +64,6 @@ class ScriptCliCompilationTest : KtUsefulTestCase() {
val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.NO_KOTLIN_REFLECT, TestJdkKind.FULL_JDK).apply {
put(MESSAGE_COLLECTOR_KEY, collector)
addKotlinSourceRoot(script.path)
if (scriptDef != null) {
val hostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) {
configurationDependencies(JvmDependency(classpath))
@@ -84,7 +78,7 @@ class ScriptCliCompilationTest : KtUsefulTestCase() {
val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
return KotlinToJVMBytecodeCompiler.compileAndExecuteScript(environment, args) to collector
return compileAndExecuteScript(script.toScriptSource(), environment, null, args) to collector
}
private fun checkRun(
@@ -1,33 +1,21 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.
* Copyright 2010-2020 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.scripts
@file:Suppress("unused")
package org.jetbrains.kotlin.scripting.compiler.test
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.daemon.TestMessageCollector
import org.jetbrains.kotlin.daemon.assertHasMessage
import org.jetbrains.kotlin.daemon.toFile
import org.jetbrains.kotlin.script.loadScriptingPlugin
import org.jetbrains.kotlin.scripting.compiler.plugin.TestMessageCollector
import org.jetbrains.kotlin.scripting.compiler.plugin.assertHasMessage
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
@@ -51,6 +39,7 @@ import kotlin.reflect.KClass
import kotlin.script.dependencies.*
import kotlin.script.experimental.dependencies.*
import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult
import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
import kotlin.script.templates.AcceptedAnnotations
import kotlin.script.templates.ScriptTemplateDefinition
@@ -72,7 +61,8 @@ class ScriptTemplateTest : KtUsefulTestCase() {
fun testScriptWithClassParameter() {
val messageCollector = TestMessageCollector()
val aClass = compileScript("fib_cp.kts", ScriptWithClassParam::class, null, runIsolated = false, messageCollector = messageCollector)
val aClass =
compileScript("fib_cp.kts", ScriptWithClassParam::class, null, runIsolated = false, messageCollector = messageCollector)
Assert.assertNotNull("Compilation failed:\n$messageCollector", aClass)
val out = captureOut {
aClass!!.getConstructor(TestParamClass::class.java).newInstance(TestParamClass(4))
@@ -82,7 +72,8 @@ class ScriptTemplateTest : KtUsefulTestCase() {
fun testScriptWithBaseClassWithParam() {
val messageCollector = TestMessageCollector()
val aClass = compileScript("fib_dsl.kts", ScriptWithBaseClass::class, null, runIsolated = false, messageCollector = messageCollector)
val aClass =
compileScript("fib_dsl.kts", ScriptWithBaseClass::class, null, runIsolated = false, messageCollector = messageCollector)
Assert.assertNotNull("Compilation failed:\n$messageCollector", aClass)
val out = captureOut {
aClass!!.getConstructor(Integer.TYPE, Integer.TYPE).newInstance(4, 1)
@@ -106,9 +97,15 @@ class ScriptTemplateTest : KtUsefulTestCase() {
val savedErr = System.err
try {
System.setErr(PrintStream(NullOutputStream()))
Assert.assertNull(compileScript("fib_ext_ann2.kts", ScriptWithIntParamAndDummyResolver::class, null, includeKotlinRuntime = false))
}
finally {
Assert.assertNull(
compileScript(
"fib_ext_ann2.kts",
ScriptWithIntParamAndDummyResolver::class,
null,
includeKotlinRuntime = false
)
)
} finally {
System.setErr(savedErr)
}
@@ -133,7 +130,12 @@ class ScriptTemplateTest : KtUsefulTestCase() {
fun testScriptWithOverriddenParam() {
val messageCollector = TestMessageCollector()
val aClass = compileScript("overridden_parameter.kts", ScriptBaseClassWithOverriddenProperty::class, null, messageCollector = messageCollector)
val aClass = compileScript(
"overridden_parameter.kts",
ScriptBaseClassWithOverriddenProperty::class,
null,
messageCollector = messageCollector
)
Assert.assertNotNull("Compilation failed:\n$messageCollector", aClass)
val out = captureOut {
aClass!!.getConstructor(Integer.TYPE).newInstance(4)
@@ -176,7 +178,8 @@ class ScriptTemplateTest : KtUsefulTestCase() {
fun testScriptWithNullableProjection() {
val messageCollector = TestMessageCollector()
val aClass = compileScript("nullable_projection.kts", ScriptWithNullableProjection::class, null, messageCollector = messageCollector)
val aClass =
compileScript("nullable_projection.kts", ScriptWithNullableProjection::class, null, messageCollector = messageCollector)
Assert.assertNotNull("Compilation failed:\n$messageCollector", aClass)
captureOut {
aClass!!.getConstructor(Array<String>::class.java).newInstance(arrayOf<String?>(null))
@@ -203,7 +206,7 @@ class ScriptTemplateTest : KtUsefulTestCase() {
captureOut {
aClass!!.getConstructor(Array<String>::class.java).newInstance(arrayOf("4", "other"))
}.let {
assertEqualsTrimmed(NUM_4_LINE + " (other)" + FIB_SCRIPT_OUTPUT_TAIL, it)
assertEqualsTrimmed("$NUM_4_LINE (other)$FIB_SCRIPT_OUTPUT_TAIL", it)
}
}
@@ -263,19 +266,34 @@ class ScriptTemplateTest : KtUsefulTestCase() {
fun testAcceptedAnnotationsSync() {
val messageCollector = TestMessageCollector()
val aClass = compileScript("acceptedAnnotations.kts", ScriptWithAcceptedAnnotationsSyncResolver::class, null, messageCollector = messageCollector)
val aClass = compileScript(
"acceptedAnnotations.kts",
ScriptWithAcceptedAnnotationsSyncResolver::class,
null,
messageCollector = messageCollector
)
Assert.assertNotNull("Compilation failed:\n$messageCollector", aClass)
}
fun testAcceptedAnnotationsAsync() {
val messageCollector = TestMessageCollector()
val aClass = compileScript("acceptedAnnotations.kts", ScriptWithAcceptedAnnotationsAsyncResolver::class, null, messageCollector = messageCollector)
val aClass = compileScript(
"acceptedAnnotations.kts",
ScriptWithAcceptedAnnotationsAsyncResolver::class,
null,
messageCollector = messageCollector
)
Assert.assertNotNull("Compilation failed:\n$messageCollector", aClass)
}
fun testAcceptedAnnotationsLegacy() {
val messageCollector = TestMessageCollector()
val aClass = compileScript("acceptedAnnotations.kts", ScriptWithAcceptedAnnotationsLegacyResolver::class, null, messageCollector = messageCollector)
val aClass = compileScript(
"acceptedAnnotations.kts",
ScriptWithAcceptedAnnotationsLegacyResolver::class,
null,
messageCollector = messageCollector
)
Assert.assertNotNull("Compilation failed:\n$messageCollector", aClass)
}
@@ -305,8 +323,7 @@ class ScriptTemplateTest : KtUsefulTestCase() {
var exceptionThrown = false
try {
tryConstructClassFromStringArgs(aClass!!, emptyList())
}
catch (e: InvocationTargetException) {
} catch (e: InvocationTargetException) {
Assert.assertTrue(e.cause is IllegalStateException)
exceptionThrown = true
}
@@ -321,17 +338,19 @@ class ScriptTemplateTest : KtUsefulTestCase() {
}
private fun compileScript(
scriptPath: String,
scriptTemplate: KClass<out Any>,
environment: Map<String, Any?>? = null,
runIsolated: Boolean = true,
messageCollector: MessageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false),
includeKotlinRuntime: Boolean = true
scriptPath: String,
scriptTemplate: KClass<out Any>,
environment: Map<String, Any?>? = null,
runIsolated: Boolean = true,
messageCollector: MessageCollector = PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false),
includeKotlinRuntime: Boolean = true
): Class<*>? =
compileScriptImpl("compiler/testData/script/" + scriptPath,
KotlinScriptDefinitionFromAnnotatedTemplate(
scriptTemplate, environment
), runIsolated, messageCollector, includeKotlinRuntime)
compileScriptImpl(
"plugins/scripting/scripting-compiler/testData/compiler/$scriptPath",
KotlinScriptDefinitionFromAnnotatedTemplate(
scriptTemplate, environment
), runIsolated, messageCollector, includeKotlinRuntime
)
private fun compileScriptImpl(
scriptPath: String,
@@ -343,13 +362,13 @@ class ScriptTemplateTest : KtUsefulTestCase() {
val rootDisposable = Disposer.newDisposable()
try {
val additionalClasspath = System.getProperty("kotlin.test.script.classpath")?.split(File.pathSeparator)
?.map{ File(it) }.orEmpty().toTypedArray()
?.map { File(it) }.orEmpty().toTypedArray()
val configuration = KotlinTestUtils.newConfiguration(
if (includeKotlinRuntime) ConfigurationKind.ALL else ConfigurationKind.JDK_ONLY,
TestJdkKind.FULL_JDK,
*additionalClasspath)
if (includeKotlinRuntime) ConfigurationKind.ALL else ConfigurationKind.JDK_ONLY,
TestJdkKind.FULL_JDK,
*additionalClasspath
)
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
configuration.addKotlinSourceRoot(scriptPath)
configuration.add(
ScriptingConfigurationKeys.SCRIPT_DEFINITIONS,
ScriptDefinition.FromLegacy(
@@ -365,7 +384,12 @@ class ScriptTemplateTest : KtUsefulTestCase() {
val environment = KotlinCoreEnvironment.createForTests(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
return try {
KotlinToJVMBytecodeCompiler.compileScript(environment, this::class.java.classLoader.takeUnless { runIsolated })
val res = compileScript(
File(scriptPath).toScriptSource(),
environment,
this::class.java.classLoader.takeUnless { runIsolated }
)
res.first?.java
} catch (e: CompilationException) {
messageCollector.report(
CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e),
@@ -388,21 +412,24 @@ class ScriptTemplateTest : KtUsefulTestCase() {
open class TestKotlinScriptDummyDependenciesResolver : DependenciesResolver {
@AcceptedAnnotations(DependsOn::class, DependsOnTwo::class)
override fun resolve(scriptContents: ScriptContents,
environment: Environment
): ResolveResult
{
override fun resolve(
scriptContents: ScriptContents,
environment: Environment
): ResolveResult {
return ScriptDependencies(
classpath = classpathFromClassloader(),
imports = listOf("org.jetbrains.kotlin.scripts.DependsOn", "org.jetbrains.kotlin.scripts.DependsOnTwo")
imports = listOf(
"org.jetbrains.kotlin.scripting.compiler.test.DependsOn",
"org.jetbrains.kotlin.scripting.compiler.test.DependsOnTwo"
)
).asSuccess()
}
}
private fun classpathFromClassloader(): List<File> =
(TestKotlinScriptDependenciesResolver::class.java.classLoader as? URLClassLoader)?.urLs
?.mapNotNull(URL::toFile)
?.filter { it.path.contains("out") && it.path.contains("test") }
(TestKotlinScriptDependenciesResolver::class.java.classLoader as? URLClassLoader)?.urLs
?.mapNotNull(URL::toFile)
?.filter { it.path.contains("out") && it.path.contains("test") }
?: emptyList()
@@ -430,7 +457,10 @@ open class TestKotlinScriptDependenciesResolver : TestKotlinScriptDummyDependenc
}
return ScriptDependencies(
classpath = classpathFromClassloader() + cp,
imports = listOf("org.jetbrains.kotlin.scripts.DependsOn", "org.jetbrains.kotlin.scripts.DependsOnTwo")
imports = listOf(
"org.jetbrains.kotlin.scripting.compiler.test.DependsOn",
"org.jetbrains.kotlin.scripting.compiler.test.DependsOnTwo"
)
).asSuccess()
}
}
@@ -439,36 +469,38 @@ class TestParamClass(@Suppress("unused") val memberNum: Int)
class ErrorReportingResolver : TestKotlinScriptDependenciesResolver() {
override fun resolve(
scriptContents: ScriptContents,
environment: Environment
scriptContents: ScriptContents,
environment: Environment
): ResolveResult {
return ResolveResult.Success(
super.resolve(scriptContents, environment).dependencies!!,
listOf(
ScriptReport("error", ScriptReport.Severity.ERROR, null),
ScriptReport("warning", ScriptReport.Severity.WARNING, ScriptReport.Position(1, 0)),
ScriptReport("info", ScriptReport.Severity.INFO, ScriptReport.Position(2, 0)),
ScriptReport("debug", ScriptReport.Severity.DEBUG, ScriptReport.Position(3, 0))
super.resolve(scriptContents, environment).dependencies!!,
listOf(
ScriptReport("error", ScriptReport.Severity.ERROR, null),
ScriptReport("warning", ScriptReport.Severity.WARNING, ScriptReport.Position(1, 0)),
ScriptReport("info", ScriptReport.Severity.INFO, ScriptReport.Position(2, 0)),
ScriptReport("debug", ScriptReport.Severity.DEBUG, ScriptReport.Position(3, 0))
)
)
)
}
}
class TestAsyncResolver : TestKotlinScriptDependenciesResolver(), AsyncDependenciesResolver {
override suspend fun resolveAsync(
scriptContents: ScriptContents,
environment: Environment
scriptContents: ScriptContents,
environment: Environment
): ResolveResult = super<TestKotlinScriptDependenciesResolver>.resolve(scriptContents, environment)
override fun resolve(scriptContents: ScriptContents, environment: Environment): ResolveResult =
super<AsyncDependenciesResolver>.resolve(scriptContents, environment)
super<AsyncDependenciesResolver>.resolve(scriptContents, environment)
}
@Target(AnnotationTarget.FILE)
annotation class TestAnno1
@Target(AnnotationTarget.FILE)
annotation class TestAnno2
@Target(AnnotationTarget.FILE)
annotation class TestAnno3
@@ -478,38 +510,38 @@ interface AcceptedAnnotationsCheck {
fun checkHasAnno1Annotation(scriptContents: ScriptContents): ResolveResult.Success {
val actualAnnotations = scriptContents.annotations
Assert.assertTrue(
"Loaded annotation: $actualAnnotations",
actualAnnotations.single().annotationClass.qualifiedName == TestAnno1::class.qualifiedName
"Loaded annotation: $actualAnnotations",
actualAnnotations.single().annotationClass.qualifiedName == TestAnno1::class.qualifiedName
)
return ScriptDependencies(
classpath = classpathFromClassloader(),
imports = annotationFqNames
classpath = classpathFromClassloader(),
imports = annotationFqNames
).asSuccess()
}
}
class TestAcceptedAnnotationsSyncResolver: DependenciesResolver, AcceptedAnnotationsCheck {
class TestAcceptedAnnotationsSyncResolver : DependenciesResolver, AcceptedAnnotationsCheck {
@AcceptedAnnotations(TestAnno1::class, TestAnno3::class)
override fun resolve(scriptContents: ScriptContents, environment: Environment): ResolveResult {
return checkHasAnno1Annotation(scriptContents)
}
}
class TestAcceptedAnnotationsAsyncResolver: AsyncDependenciesResolver, AcceptedAnnotationsCheck {
class TestAcceptedAnnotationsAsyncResolver : AsyncDependenciesResolver, AcceptedAnnotationsCheck {
@AcceptedAnnotations(TestAnno1::class, TestAnno3::class)
override suspend fun resolveAsync(scriptContents: ScriptContents, environment: Environment): ResolveResult {
return checkHasAnno1Annotation(scriptContents)
}
}
class TestAcceptedAnnotationsLegacyResolver: ScriptDependenciesResolver, AcceptedAnnotationsCheck {
class TestAcceptedAnnotationsLegacyResolver : ScriptDependenciesResolver, AcceptedAnnotationsCheck {
@AcceptedAnnotations(TestAnno1::class, TestAnno3::class)
override fun resolve(
script: ScriptContents,
environment: Environment?,
report: (ScriptDependenciesResolver.ReportSeverity, String, ScriptContents.Position?) -> Unit,
previousDependencies: KotlinScriptExternalDependencies?
script: ScriptContents,
environment: Environment?,
report: (ScriptDependenciesResolver.ReportSeverity, String, ScriptContents.Position?) -> Unit,
previousDependencies: KotlinScriptExternalDependencies?
): Future<KotlinScriptExternalDependencies?> {
checkHasAnno1Annotation(script)
return object : KotlinScriptExternalDependencies {
@@ -522,51 +554,58 @@ class TestAcceptedAnnotationsLegacyResolver: ScriptDependenciesResolver, Accepte
}
}
class SeveralConstructorsResolver(val c: Int): TestKotlinScriptDependenciesResolver() {
constructor(): this(0)
class SeveralConstructorsResolver(val c: Int) : TestKotlinScriptDependenciesResolver() {
constructor() : this(0)
}
class DefaultArgsConstructorResolver(val c: Int = 0): TestKotlinScriptDependenciesResolver()
class ThrowingResolver: DependenciesResolver {
class DefaultArgsConstructorResolver(val c: Int = 0) : TestKotlinScriptDependenciesResolver()
class ThrowingResolver : DependenciesResolver {
override fun resolve(scriptContents: ScriptContents, environment: Environment): ResolveResult {
throw IllegalStateException("Exception from resolver")
}
}
@ScriptTemplateDefinition(
scriptFilePattern =".*\\.kts",
resolver = TestKotlinScriptDummyDependenciesResolver::class)
scriptFilePattern = ".*\\.kts",
resolver = TestKotlinScriptDummyDependenciesResolver::class
)
abstract class ScriptWithIntParamAndDummyResolver(val num: Int)
@ScriptTemplateDefinition(
scriptFilePattern =".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class)
scriptFilePattern = ".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
)
abstract class ScriptWithIntParam(val num: Int)
@ScriptTemplateDefinition(
scriptFilePattern =".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class)
scriptFilePattern = ".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
)
abstract class ScriptWithClassParam(val param: TestParamClass)
@ScriptTemplateDefinition(
scriptFilePattern =".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class)
scriptFilePattern = ".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
)
abstract class ScriptWithBaseClass(val num: Int, passthrough: Int) : TestDSLClassWithParam(passthrough)
@ScriptTemplateDefinition(
scriptFilePattern =".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class)
scriptFilePattern = ".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
)
abstract class ScriptWithoutParams(@Suppress("UNUSED_PARAMETER") num: Int)
@ScriptTemplateDefinition(
scriptFilePattern =".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class)
scriptFilePattern = ".*\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
)
abstract class ScriptBaseClassWithOverriddenProperty(override val num: Int) : TestClassWithOverridableProperty(num)
@ScriptTemplateDefinition(
scriptFilePattern = ".*\\.custom\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
scriptFilePattern = ".*\\.custom\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class
)
abstract class ScriptWithDifferentFileNamePattern
@@ -618,7 +657,15 @@ annotation class DependsOn(val path: String)
annotation class DependsOnTwo(val unused: String = "", val path1: String = "", val path2: String = "")
private class NullOutputStream : OutputStream() {
override fun write(b: Int) { }
override fun write(b: ByteArray) { }
override fun write(b: ByteArray, off: Int, len: Int) { }
override fun write(b: Int) {}
override fun write(b: ByteArray) {}
override fun write(b: ByteArray, off: Int, len: Int) {}
}
internal fun URL.toFile() =
try {
File(toURI().schemeSpecificPart)
} catch (e: java.net.URISyntaxException) {
if (protocol != "file") null
else File(file)
}
@@ -1,28 +1,15 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* 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.
* Copyright 2010-2020 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.scripts
package org.jetbrains.kotlin.scripting.compiler.test
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.codegen.CompilationException
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.script.loadScriptingPlugin
@@ -38,6 +25,7 @@ import org.jetbrains.kotlin.utils.tryConstructClassFromStringArgs
import org.junit.Assert
import java.io.File
import java.net.URLClassLoader
import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
class ScriptTest : KtUsefulTestCase() {
@@ -48,7 +36,7 @@ class ScriptTest : KtUsefulTestCase() {
val anObj = tryConstructClassFromStringArgs(aClass!!, listOf("4", "comment"))
Assert.assertNotNull(anObj)
}
assertEqualsTrimmed(NUM_4_LINE + " (comment)" + FIB_SCRIPT_OUTPUT_TAIL, out)
assertEqualsTrimmed("$NUM_4_LINE (comment)$FIB_SCRIPT_OUTPUT_TAIL", out)
}
fun testStandardScriptWithoutParams() {
@@ -58,7 +46,7 @@ class ScriptTest : KtUsefulTestCase() {
val anObj = tryConstructClassFromStringArgs(aClass!!, emptyList())
Assert.assertNotNull(anObj)
}
assertEqualsTrimmed(NUM_4_LINE + " (none)" + FIB_SCRIPT_OUTPUT_TAIL, out)
assertEqualsTrimmed("$NUM_4_LINE (none)$FIB_SCRIPT_OUTPUT_TAIL", out)
}
fun testStandardScriptWithSaving() {
@@ -70,7 +58,7 @@ class ScriptTest : KtUsefulTestCase() {
val anObj = tryConstructClassFromStringArgs(aClass!!, emptyList())
Assert.assertNotNull(anObj)
}
assertEqualsTrimmed(NUM_4_LINE + " (none)" + FIB_SCRIPT_OUTPUT_TAIL, out1)
assertEqualsTrimmed("$NUM_4_LINE (none)$FIB_SCRIPT_OUTPUT_TAIL", out1)
val savedClassLoader = URLClassLoader(arrayOf(tmpdir.toURI().toURL()), aClass!!.classLoader)
val aClassSaved = savedClassLoader.loadClass(aClass.name)
Assert.assertNotNull(aClassSaved)
@@ -78,7 +66,7 @@ class ScriptTest : KtUsefulTestCase() {
val anObjSaved = tryConstructClassFromStringArgs(aClassSaved!!, emptyList())
Assert.assertNotNull(anObjSaved)
}
assertEqualsTrimmed(NUM_4_LINE + " (none)" + FIB_SCRIPT_OUTPUT_TAIL, out2)
assertEqualsTrimmed("$NUM_4_LINE (none)$FIB_SCRIPT_OUTPUT_TAIL", out2)
}
fun testUseCompilerInternals() {
@@ -96,14 +84,13 @@ class ScriptTest : KtUsefulTestCase() {
saveClassesDir: File? = null
): Class<*>? {
val messageCollector =
if (suppressOutput) MessageCollector.NONE
else PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false)
if (suppressOutput) MessageCollector.NONE
else PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false)
val rootDisposable = Disposer.newDisposable()
try {
val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.FULL_JDK)
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector)
configuration.addKotlinSourceRoot("compiler/testData/script/$scriptPath")
configuration.add(
ScriptingConfigurationKeys.SCRIPT_DEFINITIONS,
ScriptDefinition.FromLegacy(
@@ -121,19 +108,22 @@ class ScriptTest : KtUsefulTestCase() {
val environment = KotlinCoreEnvironment.createForTests(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
try {
return KotlinToJVMBytecodeCompiler.compileScript(environment, this::class.java.classLoader.takeUnless { runIsolated })
}
catch (e: CompilationException) {
messageCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e),
MessageUtil.psiElementToMessageLocation(e.element))
return compileScript(
File("plugins/scripting/scripting-compiler/testData/compiler/$scriptPath").toScriptSource(),
environment,
this::class.java.classLoader.takeUnless { runIsolated }
).first?.java
} catch (e: CompilationException) {
messageCollector.report(
CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(e),
MessageUtil.psiElementToMessageLocation(e.element)
)
return null
}
catch (t: Throwable) {
} catch (t: Throwable) {
MessageCollectorUtil.reportException(messageCollector, t)
throw t
}
}
finally {
} finally {
Disposer.dispose(rootDisposable)
}
}
@@ -16,7 +16,7 @@
@file:Suppress("unused")
package org.jetbrains.kotlin.scripts
package org.jetbrains.kotlin.scripting.compiler.test
open class TestDSLClass
@@ -0,0 +1,106 @@
/*
* Copyright 2010-2020 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.compiler.test
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.scripting.compiler.plugin.impl.ScriptJvmCompilerFromEnvironment
import org.jetbrains.kotlin.scripting.compiler.plugin.toCompilerMessageSeverity
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider
import org.jetbrains.kotlin.utils.tryConstructClassFromStringArgs
import org.junit.Assert
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import kotlin.reflect.KClass
import kotlin.script.experimental.api.SourceCode
import kotlin.script.experimental.api.onSuccess
import kotlin.script.experimental.api.valueOr
import kotlin.script.experimental.api.with
import kotlin.script.experimental.jvm.baseClassLoader
import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
import kotlin.script.experimental.jvm.jvm
internal const val NUM_4_LINE = "num: 4"
internal const val FIB_SCRIPT_OUTPUT_TAIL =
"""
fib(1)=1
fib(0)=1
fib(2)=2
fib(1)=1
fib(3)=3
fib(1)=1
fib(0)=1
fib(2)=2
fib(4)=5
"""
internal fun captureOut(body: () -> Unit): String {
val outStream = ByteArrayOutputStream()
val prevOut = System.out
System.setOut(PrintStream(outStream))
try {
body()
} finally {
System.out.flush()
System.setOut(prevOut)
}
return outStream.toString()
}
private fun String.linesSplitTrim() =
split('\n', '\r').map(String::trim).filter(String::isNotBlank)
internal fun assertEqualsTrimmed(expected: String, actual: String) =
Assert.assertEquals(expected.linesSplitTrim(), actual.linesSplitTrim())
// TODO: rewrite tests to avoid emulated old behavior
internal fun compileScript(
script: SourceCode,
environment: KotlinCoreEnvironment,
parentClassLoader: ClassLoader?
): Pair<KClass<*>?, ExitCode> {
val scriptCompiler = ScriptJvmCompilerFromEnvironment(environment)
val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]!!
val scriptDefinition = ScriptDefinitionProvider.getInstance(environment.project)!!.findDefinition(script)!!
val scriptCompilationConfiguration = scriptDefinition.compilationConfiguration.with {
jvm {
dependenciesFromCurrentContext(wholeClasspath = true)
}
}
val compiledScript = scriptCompiler.compile(script, scriptCompilationConfiguration).onSuccess {
runBlocking {
it.getClass(scriptDefinition.evaluationConfiguration.with {
jvm {
baseClassLoader(parentClassLoader)
}
})
}
}.valueOr {
for (report in it.reports) {
messageCollector.report(report.severity.toCompilerMessageSeverity(), report.render(withSeverity = false))
}
return null to ExitCode.COMPILATION_ERROR
}
return compiledScript to ExitCode.OK
}
// TODO: rewrite tests to avoid emulated old behavior
internal fun compileAndExecuteScript(
script: SourceCode,
environment: KotlinCoreEnvironment,
parentClassLoader: ClassLoader?,
scriptArgs: List<String>
): ExitCode {
val (compiled, code) = compileScript(script, environment, parentClassLoader)
if (compiled == null || code != ExitCode.OK) return code
return if (tryConstructClassFromStringArgs(compiled.java, scriptArgs) != null) ExitCode.OK else ExitCode.INTERNAL_ERROR
}