| /* |
| * Copyright 2010-2018 JetBrains s.r.o. 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.codegen |
| |
| import org.jetbrains.kotlin.cli.common.messages.MessageCollector |
| import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots |
| import org.jetbrains.kotlin.config.CompilerConfiguration |
| import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContextOrStlib |
| import org.jetbrains.kotlin.scripting.compiler.plugin.configureScriptDefinitions |
| import org.jetbrains.kotlin.test.ConfigurationKind |
| import org.jetbrains.kotlin.test.InTextDirectivesUtils |
| import org.jetbrains.kotlin.test.TestJdkKind |
| import org.jetbrains.kotlin.utils.PathUtil |
| import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMMON_JAR |
| import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR |
| import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_JVM_JAR |
| import org.junit.Assert |
| import java.io.File |
| import kotlin.script.experimental.annotations.KotlinScript |
| import kotlin.script.experimental.api.ScriptCompilationConfiguration |
| import kotlin.script.experimental.api.implicitReceivers |
| import kotlin.script.experimental.api.providedProperties |
| |
| abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { |
| private lateinit var scriptDefinitions: List<String> |
| |
| override fun setUp() { |
| super.setUp() |
| |
| configurationKind = ConfigurationKind.ALL |
| } |
| |
| override fun updateConfiguration(configuration: CompilerConfiguration) { |
| if (scriptDefinitions.isNotEmpty()) { |
| configureScriptDefinitions(scriptDefinitions, configuration, this::class.java.classLoader, MessageCollector.NONE, emptyMap()) |
| } |
| |
| configuration.addJvmClasspathRoots(additionalDependencies.orEmpty()) |
| } |
| |
| override fun doMultiFileTest(wholeFile: File, files: MutableList<TestFile>, javaFilesDir: File?) { |
| if (files.size > 1) { |
| throw UnsupportedOperationException("Multiple files are not yet supported in this test") |
| } |
| |
| val file = files.single() |
| val content = file.content |
| |
| scriptDefinitions = InTextDirectivesUtils.findListWithPrefixes(content, "KOTLIN_SCRIPT_DEFINITION:") |
| if (scriptDefinitions.isNotEmpty()) { |
| additionalDependencies = |
| scriptCompilationClasspathFromContextOrStlib("tests-common", "kotlin-stdlib") + |
| File(TestScriptWithReceivers::class.java.protectionDomain.codeSource.location.toURI().path) + |
| with(PathUtil.kotlinPathsForDistDirectory) { |
| arrayOf( |
| KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMMON_JAR, |
| KOTLIN_SCRIPTING_JVM_JAR |
| ).mapNotNull { File(libPath, it).takeIf { it.exists() } } |
| } |
| } |
| |
| createEnvironmentWithMockJdkAndIdeaAnnotations(configurationKind, files, TestJdkKind.FULL_JDK) |
| |
| myFiles = CodegenTestFiles.create(file.name, content, myEnvironment.project) |
| |
| try { |
| val scriptClass = generateClass(myFiles.psiFile.script!!.fqName.asString()) |
| |
| // TODO: add types to receivers, envVars and params |
| val receivers = InTextDirectivesUtils.findListWithPrefixes(content, "receiver:") |
| val environmentVars = extractAllKeyValPairs(content, "envVar:") |
| val scriptParams = InTextDirectivesUtils.findListWithPrefixes(content, "param:") |
| val scriptInstance = runScript(scriptClass, receivers, environmentVars, scriptParams) |
| |
| val expectedFields = extractAllKeyValPairs(content, "expected:") |
| checkExpectedFields(expectedFields, scriptClass, scriptInstance) |
| } catch (e: Throwable) { |
| println(generateToText()) |
| throw e |
| } |
| } |
| |
| private fun extractAllKeyValPairs(content: String, directive: String): Map<String, String> = |
| InTextDirectivesUtils.findListWithPrefixes(content, directive).associate { line -> |
| line.substringBefore('=') to line.substringAfter('=') |
| } |
| |
| private fun runScript(scriptClass: Class<*>, receivers: List<Any?>, environmentVars: Map<String, Any?>, scriptParams: List<Any>): Any? { |
| |
| val ctorParams = arrayListOf<Any?>() |
| ctorParams.addAll(scriptParams) |
| ctorParams.addAll(receivers) |
| ctorParams.addAll(environmentVars.values) |
| |
| val constructor = scriptClass.constructors[0] |
| return constructor.newInstance(*ctorParams.toTypedArray()) |
| } |
| |
| private fun checkExpectedFields(expectedFields: Map<String, Any?>, scriptClass: Class<*>, scriptInstance: Any?) { |
| Assert.assertFalse("expecting at least one expectation", expectedFields.isEmpty()) |
| |
| for ((fieldName, expectedValue) in expectedFields) { |
| |
| if (expectedValue == "<nofield>") { |
| try { |
| scriptClass.getDeclaredField(fieldName) |
| Assert.fail("must have no field $fieldName") |
| } catch (e: NoSuchFieldException) { |
| continue |
| } |
| } |
| |
| val field = scriptClass.getDeclaredField(fieldName) |
| field.isAccessible = true |
| val resultString = field.get(scriptInstance)?.toString() ?: "null" |
| Assert.assertEquals("comparing field $fieldName", expectedValue, resultString) |
| } |
| } |
| } |
| |
| object TestScriptWithReceiversConfiguration : ScriptCompilationConfiguration( |
| { |
| implicitReceivers(String::class) |
| }) |
| |
| @Suppress("unused") |
| @KotlinScript(compilationConfiguration = TestScriptWithReceiversConfiguration::class) |
| abstract class TestScriptWithReceivers |
| |
| object TestScriptWithSimpleEnvVarsConfiguration : ScriptCompilationConfiguration( |
| { |
| providedProperties("stringVar1" to String::class) |
| }) |
| |
| @Suppress("unused") |
| @KotlinScript(compilationConfiguration = TestScriptWithSimpleEnvVarsConfiguration::class) |
| abstract class TestScriptWithSimpleEnvVars |
| |
| @Suppress("unused") |
| @KotlinScript(fileExtension = "customext") |
| abstract class TestScriptWithNonKtsExtension(val name: String) |