[JS IR BE] Support two versions of test runtime: full and reduced

This commit is contained in:
Svyatoslav Kuzmich
2019-01-23 16:28:12 +03:00
parent a40448aebc
commit 29eb3c745c
7 changed files with 258 additions and 139 deletions
@@ -104,6 +104,12 @@ abstract class BasicBoxTest(
fileContent = fileContent.replace("COROUTINES_PACKAGE", coroutinesPackage)
}
val runtimeType =
if (KJS_WITH_FULL_RUNTIME.matcher(fileContent).find())
JsIrTestRuntime.FULL
else
JsIrTestRuntime.DEFAULT
val actualMainCallParameters = if (CALL_MAIN_PATTERN.matcher(fileContent).find()) MainCallParameters.mainWithArguments(listOf("testArg")) else mainCallParameters
val outputPrefixFile = getOutputPrefixFile(filePath)
@@ -128,7 +134,8 @@ abstract class BasicBoxTest(
generateJavaScriptFile(
file.parent, module, outputFileName, dependencies, friends, modules.size > 1,
!SKIP_SOURCEMAP_REMAPPING.matcher(fileContent).find(),
outputPrefixFile, outputPostfixFile, actualMainCallParameters, testPackage, testFunction
outputPrefixFile, outputPostfixFile, actualMainCallParameters, testPackage, testFunction,
runtimeType
)
if (!module.name.endsWith(OLD_MODULE_SUFFIX)) Pair(outputFileName, module) else null
@@ -182,7 +189,7 @@ abstract class BasicBoxTest(
}
if (!dontRunGeneratedCode) {
runGeneratedCode(allJsFiles, mainModuleName, testPackage, testFunction, expectedResult, withModuleSystem)
runGeneratedCode(allJsFiles, mainModuleName, testPackage, testFunction, expectedResult, withModuleSystem, runtimeType)
}
performAdditionalChecks(generatedJsFiles.map { it.first }, outputPrefixFile, outputPostfixFile)
@@ -235,12 +242,13 @@ abstract class BasicBoxTest(
}
protected open fun runGeneratedCode(
jsFiles: List<String>,
testModuleName: String?,
testPackage: String?,
testFunction: String,
expectedResult: String,
withModuleSystem: Boolean
jsFiles: List<String>,
testModuleName: String?,
testPackage: String?,
testFunction: String,
expectedResult: String,
withModuleSystem: Boolean,
runtime: JsIrTestRuntime
) {
NashornJsTestChecker.check(jsFiles, testModuleName, testPackage, testFunction, expectedResult, withModuleSystem)
}
@@ -306,7 +314,8 @@ abstract class BasicBoxTest(
outputPostfixFile: File?,
mainCallParameters: MainCallParameters,
testPackage: String?,
testFunction: String
testFunction: String,
runtime: JsIrTestRuntime
) {
val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") }
val testFiles = kotlinFiles.map { it.fileName }
@@ -328,32 +337,33 @@ abstract class BasicBoxTest(
val incrementalData = IncrementalData()
translateFiles(
psiFiles.map(TranslationUnit::SourceFile), outputFile, config, outputPrefixFile, outputPostfixFile,
mainCallParameters, incrementalData, remap, testPackage, testFunction
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime
)
if (incrementalCompilationChecksEnabled && module.hasFilesToRecompile) {
checkIncrementalCompilation(
sourceDirs, module, kotlinFiles, dependencies, friends, multiModule, remap,
outputFile, outputPrefixFile, outputPostfixFile, mainCallParameters, incrementalData, testPackage, testFunction
outputFile, outputPrefixFile, outputPostfixFile, mainCallParameters, incrementalData, testPackage, testFunction, runtime
)
}
}
private fun checkIncrementalCompilation(
sourceDirs: List<String>,
module: TestModule,
kotlinFiles: List<TestFile>,
dependencies: List<String>,
friends: List<String>,
multiModule: Boolean,
remap: Boolean,
outputFile: File,
outputPrefixFile: File?,
outputPostfixFile: File?,
mainCallParameters: MainCallParameters,
incrementalData: IncrementalData,
testPackage: String?,
testFunction: String
sourceDirs: List<String>,
module: TestModule,
kotlinFiles: List<TestFile>,
dependencies: List<String>,
friends: List<String>,
multiModule: Boolean,
remap: Boolean,
outputFile: File,
outputPrefixFile: File?,
outputPostfixFile: File?,
mainCallParameters: MainCallParameters,
incrementalData: IncrementalData,
testPackage: String?,
testFunction: String,
runtime: JsIrTestRuntime
) {
val sourceToTranslationUnit = hashMapOf<File, TranslationUnit>()
for (testFile in kotlinFiles) {
@@ -375,7 +385,7 @@ abstract class BasicBoxTest(
translateFiles(
translationUnits, recompiledOutputFile, recompiledConfig, outputPrefixFile, outputPostfixFile,
mainCallParameters, incrementalData, remap, testPackage, testFunction
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime
)
val originalOutput = FileUtil.loadFile(outputFile)
@@ -439,7 +449,8 @@ abstract class BasicBoxTest(
incrementalData: IncrementalData,
remap: Boolean,
testPackage: String?,
testFunction: String
testFunction: String,
runtime: JsIrTestRuntime
) {
val translator = K2JSTranslator(config)
val translationResult = translator.translateUnits(ExceptionThrowingReporter, units, mainCallParameters)
@@ -776,6 +787,7 @@ abstract class BasicBoxTest(
private val RECOMPILE_PATTERN = Pattern.compile("^// *RECOMPILE *$", Pattern.MULTILINE)
private val SOURCE_MAP_SOURCE_EMBEDDING = Regex("^// *SOURCE_MAP_EMBED_SOURCES: ([A-Z]+)*\$", RegexOption.MULTILINE)
private val CALL_MAIN_PATTERN = Pattern.compile("^// *CALL_MAIN *$", Pattern.MULTILINE)
private val KJS_WITH_FULL_RUNTIME = Pattern.compile("^// *KJS_WITH_FULL_RUNTIME *\$", Pattern.MULTILINE)
val TEST_MODULE = "JS_TESTS"
private val DEFAULT_MODULE = "main"
@@ -16,80 +16,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.test.TargetBackend
import java.io.File
private val runtimeSources = listOfKtFilesFrom(
"core/builtins/src/kotlin",
"libraries/stdlib/common/src",
"libraries/stdlib/src/kotlin/",
"libraries/stdlib/js/src/kotlin",
"libraries/stdlib/js/src/generated",
"libraries/stdlib/js/irRuntime",
"libraries/stdlib/js/runtime",
"libraries/stdlib/unsigned",
"core/builtins/native/kotlin/Annotation.kt",
"core/builtins/native/kotlin/Number.kt",
"core/builtins/native/kotlin/Comparable.kt",
"core/builtins/native/kotlin/Collections.kt",
"core/builtins/native/kotlin/Iterator.kt",
"core/builtins/native/kotlin/CharSequence.kt",
"core/builtins/src/kotlin/Unit.kt",
BasicBoxTest.COMMON_FILES_DIR_PATH
) - listOfKtFilesFrom(
"libraries/stdlib/common/src/kotlin/JvmAnnotationsH.kt",
"libraries/stdlib/src/kotlin/annotations/Multiplatform.kt",
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt",
// TODO: Support Int.pow
"libraries/stdlib/js/src/kotlin/random/PlatformRandom.kt",
// Fails with: EXPERIMENTAL_IS_NOT_ENABLED
"libraries/stdlib/common/src/kotlin/annotations/Annotations.kt",
// Conflicts with libraries/stdlib/js/src/kotlin/annotations.kt
"libraries/stdlib/js/runtime/hacks.kt",
// TODO: Reuse in IR BE
"libraries/stdlib/js/runtime/Enum.kt",
// JS-specific optimized version of emptyArray() already defined
"core/builtins/src/kotlin/ArrayIntrinsics.kt",
// Unnecessary for now
"libraries/stdlib/js/src/kotlin/dom",
"libraries/stdlib/js/src/kotlin/browser",
// TODO: fix compilation issues in arrayPlusCollection
// Replaced with irRuntime/kotlinHacks.kt
"libraries/stdlib/js/src/kotlin/kotlin.kt",
"libraries/stdlib/js/src/kotlin/currentBeMisc.kt",
// IR BE has its own generated sources
"libraries/stdlib/js/src/generated",
"libraries/stdlib/js/src/kotlin/collectionsExternal.kt",
// Full version is defined in stdlib
// This file is useful for smaller subset of runtime sources
"libraries/stdlib/js/irRuntime/rangeExtensions.kt",
// Mostly array-specific stuff
"libraries/stdlib/js/src/kotlin/builtins.kt",
// coroutines
// TODO: merge coroutines_13 with JS BE coroutines
"libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt",
"libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt",
// Inlining of js fun doesn't update the variables inside
"libraries/stdlib/js/src/kotlin/jsTypeOf.kt",
"libraries/stdlib/js/src/kotlin/collections/utils.kt"
)
private var runtimeResult: Result? = null
private val runtimeFile = File("js/js.translator/testData/out/irBox/testRuntime.js")
private var runtimeResults = mutableMapOf<JsIrTestRuntime, Result>()
abstract class BasicIrBoxTest(
pathToTestDir: String,
@@ -129,7 +56,8 @@ abstract class BasicIrBoxTest(
incrementalData: IncrementalData,
remap: Boolean,
testPackage: String?,
testFunction: String
testFunction: String,
runtime: JsIrTestRuntime
) {
val filesToCompile = units
.map { (it as TranslationUnit.SourceFile).file }
@@ -161,15 +89,17 @@ abstract class BasicIrBoxTest(
)
)
if (runtimeResult == null) {
val runtimeFile = File(runtime.path)
val runtimeResult = runtimeResults.getOrPut(runtime) {
runtimeConfiguration.put(CommonConfigurationKeys.MODULE_NAME, "JS_IR_RUNTIME")
runtimeResult = compile(config.project, runtimeSources.map(::createPsiFile), runtimeConfiguration)
runtimeFile.write(runtimeResult!!.generatedCode)
val result = compile(config.project, runtime.sources.map(::createPsiFile), runtimeConfiguration)
runtimeFile.write(result.generatedCode)
result
}
val dependencyNames = config.configuration[JSConfigurationKeys.LIBRARIES]!!.map { File(it).name }
val dependencies = listOf(runtimeResult!!.moduleDescriptor) + dependencyNames.mapNotNull { compilationCache[it]?.moduleDescriptor }
val irDependencies = listOf(runtimeResult!!.moduleFragment) + compilationCache.values.map { it.moduleFragment }
val dependencies = listOf(runtimeResult.moduleDescriptor) + dependencyNames.mapNotNull { compilationCache[it]?.moduleDescriptor }
val irDependencies = listOf(runtimeResult.moduleFragment) + compilationCache.values.map { it.moduleFragment }
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE, setOf("UnitMaterializationLowering"))
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_BEFORE, setOf("ReturnableBlockLowering"))
@@ -182,11 +112,15 @@ abstract class BasicIrBoxTest(
config.configuration,
FqName((testPackage?.let { "$it." } ?: "") + testFunction),
dependencies,
irDependencies)
irDependencies
)
compilationCache[outputFile.name.replace(".js", ".meta.js")] = result
outputFile.write(result.generatedCode)
// Prefix to help node.js runner find runtime
val runtimePrefix = "// RUNTIME: [\"${runtimeFile.path}\"]\n"
outputFile.write(runtimePrefix + result.generatedCode)
}
override fun runGeneratedCode(
@@ -195,24 +129,15 @@ abstract class BasicIrBoxTest(
testPackage: String?,
testFunction: String,
expectedResult: String,
withModuleSystem: Boolean
withModuleSystem: Boolean,
runtime: JsIrTestRuntime
) {
// TODO: should we do anything special for module systems?
// TODO: return list of js from translateFiles and provide then to this function with other js files
NashornIrJsTestChecker.check(jsFiles, null, null, testFunction, expectedResult, false)
nashornIrJsTestCheckers[runtime]!!.check(jsFiles, null, null, testFunction, expectedResult, false)
}
}
private fun listOfKtFilesFrom(vararg paths: String): List<String> {
val currentDir = File(".")
return paths.flatMap { path ->
File(path)
.walkTopDown()
.filter { it.extension == "kt" }
.map { it.relativeToOrSelf(currentDir).path }
.asIterable()
}.distinct()
}
private fun File.write(text: String) {
parentFile.mkdirs()
@@ -0,0 +1,159 @@
/*
* Copyright 2010-2019 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.js.test
import java.io.File
private const val runtimeDir = "js/js.translator/testData/out/irBox"
enum class JsIrTestRuntime(
val sources: List<String>,
val path: String
) {
// Includes all built-ins and reduced subset of stdlib
DEFAULT(
sources = reducedRuntimeSources,
path = "$runtimeDir/testRuntime.js"
),
// Includes almost full stdlib
FULL(
sources = fullRuntimeSources,
path = "$runtimeDir/testRuntimeFull.js"
)
}
private val fullRuntimeSources = listOfKtFilesFrom(
"core/builtins/src/kotlin",
"libraries/stdlib/common/src",
"libraries/stdlib/src/kotlin/",
"libraries/stdlib/js/src/kotlin",
"libraries/stdlib/js/src/generated",
"libraries/stdlib/js/irRuntime",
"libraries/stdlib/js/runtime",
"libraries/stdlib/unsigned",
"core/builtins/native/kotlin/Annotation.kt",
"core/builtins/native/kotlin/Number.kt",
"core/builtins/native/kotlin/Comparable.kt",
"core/builtins/native/kotlin/Collections.kt",
"core/builtins/native/kotlin/Iterator.kt",
"core/builtins/native/kotlin/CharSequence.kt",
"core/builtins/src/kotlin/Unit.kt",
BasicBoxTest.COMMON_FILES_DIR_PATH
) - listOfKtFilesFrom(
"libraries/stdlib/common/src/kotlin/JvmAnnotationsH.kt",
"libraries/stdlib/src/kotlin/annotations/Multiplatform.kt",
"libraries/stdlib/common/src/kotlin/NativeAnnotationsH.kt",
// TODO: Support Int.pow
"libraries/stdlib/js/src/kotlin/random/PlatformRandom.kt",
// Fails with: EXPERIMENTAL_IS_NOT_ENABLED
"libraries/stdlib/common/src/kotlin/annotations/Annotations.kt",
// Conflicts with libraries/stdlib/js/src/kotlin/annotations.kt
"libraries/stdlib/js/runtime/hacks.kt",
// TODO: Reuse in IR BE
"libraries/stdlib/js/runtime/Enum.kt",
// JS-specific optimized version of emptyArray() already defined
"core/builtins/src/kotlin/ArrayIntrinsics.kt",
// Unnecessary for now
"libraries/stdlib/js/src/kotlin/dom",
"libraries/stdlib/js/src/kotlin/browser",
// TODO: fix compilation issues in arrayPlusCollection
// Replaced with irRuntime/kotlinHacks.kt
"libraries/stdlib/js/src/kotlin/kotlin.kt",
"libraries/stdlib/js/src/kotlin/currentBeMisc.kt",
// IR BE has its own generated sources
"libraries/stdlib/js/src/generated",
"libraries/stdlib/js/src/kotlin/collectionsExternal.kt",
// Full version is defined in stdlib
// This file is useful for smaller subset of runtime sources
"libraries/stdlib/js/irRuntime/rangeExtensions.kt",
// Mostly array-specific stuff
"libraries/stdlib/js/src/kotlin/builtins.kt",
// coroutines
// TODO: merge coroutines_13 with JS BE coroutines
"libraries/stdlib/js/src/kotlin/coroutines/intrinsics/IntrinsicsJs.kt",
"libraries/stdlib/js/src/kotlin/coroutines/CoroutineImpl.kt",
// Inlining of js fun doesn't update the variables inside
"libraries/stdlib/js/src/kotlin/jsTypeOf.kt",
"libraries/stdlib/js/src/kotlin/collections/utils.kt",
// TODO: Remove stub
"libraries/stdlib/js/src/kotlin/builtins.kt"
)
val reducedRuntimeSources = fullRuntimeSources - listOfKtFilesFrom(
"libraries/stdlib/unsigned",
"core/builtins/src/kotlin/reflect/KParameter.kt",
"core/builtins/src/kotlin/reflect/KType.kt",
"core/builtins/src/kotlin/reflect/KTypeParameter.kt",
"core/builtins/src/kotlin/reflect/KVisibility.kt",
"libraries/stdlib/common/src/generated/_Arrays.kt",
"libraries/stdlib/common/src/generated/_Collections.kt",
"libraries/stdlib/common/src/generated/_Maps.kt",
"libraries/stdlib/common/src/generated/_Sequences.kt",
"libraries/stdlib/common/src/generated/_Sets.kt",
"libraries/stdlib/common/src/generated/_Strings.kt",
"libraries/stdlib/common/src/generated/_UArrays.kt",
"libraries/stdlib/common/src/generated/_URanges.kt",
"libraries/stdlib/common/src/kotlin/SequencesH.kt",
"libraries/stdlib/common/src/kotlin/TextH.kt",
"libraries/stdlib/common/src/kotlin/collections/",
"libraries/stdlib/common/src/kotlin/ioH.kt",
"libraries/stdlib/js/irRuntime/collectionsHacks.kt",
"libraries/stdlib/js/irRuntime/generated/",
"libraries/stdlib/js/src/kotlin/char.kt",
"libraries/stdlib/js/src/kotlin/collections.kt",
"libraries/stdlib/js/src/kotlin/collections/",
"libraries/stdlib/js/src/kotlin/console.kt",
"libraries/stdlib/js/src/kotlin/coreDeprecated.kt",
"libraries/stdlib/js/src/kotlin/date.kt",
"libraries/stdlib/js/src/kotlin/debug.kt",
"libraries/stdlib/js/src/kotlin/grouping.kt",
"libraries/stdlib/js/src/kotlin/json.kt",
"libraries/stdlib/js/src/kotlin/numberConversions.kt",
"libraries/stdlib/js/src/kotlin/promise.kt",
"libraries/stdlib/js/src/kotlin/regex.kt",
"libraries/stdlib/js/src/kotlin/regexp.kt",
"libraries/stdlib/js/src/kotlin/sequence.kt",
"libraries/stdlib/js/src/kotlin/string.kt",
"libraries/stdlib/js/src/kotlin/stringsCode.kt",
"libraries/stdlib/js/src/kotlin/text.kt",
"libraries/stdlib/src/kotlin/collections/",
"libraries/stdlib/src/kotlin/experimental/bitwiseOperations.kt",
"libraries/stdlib/src/kotlin/properties/Delegates.kt",
"libraries/stdlib/src/kotlin/random/URandom.kt",
"libraries/stdlib/src/kotlin/text/",
"libraries/stdlib/src/kotlin/util/KotlinVersion.kt",
"libraries/stdlib/src/kotlin/util/Tuples.kt",
"libraries/stdlib/common/src/generated/_Comparisons.kt"
)
private fun listOfKtFilesFrom(vararg paths: String): List<String> {
val currentDir = File(".")
return paths.flatMap { path ->
File(path)
.walkTopDown()
.filter { it.extension == "kt" }
.map { it.relativeToOrSelf(currentDir).path }
.asIterable()
}.distinct()
}
@@ -161,16 +161,20 @@ object NashornJsTestChecker : AbstractNashornJsTestChecker() {
}
}
object NashornIrJsTestChecker : AbstractNashornJsTestChecker() {
class NashornIrJsTestChecker(private val runtime: JsIrTestRuntime) : AbstractNashornJsTestChecker() {
override fun createScriptEngineForTest(): ScriptEngine {
val engine = createScriptEngine()
listOf(
BasicBoxTest.TEST_DATA_DIR_PATH + "nashorn-polyfills.js",
"libraries/stdlib/js/src/js/polyfills.js",
"js/js.translator/testData/out/irBox/testRuntime.js"
runtime.path
).forEach(engine::loadFile)
return engine
}
}
val nashornIrJsTestCheckers = JsIrTestRuntime.values().associate {
it to NashornIrJsTestChecker(it)
}
@@ -9,6 +9,7 @@ import com.google.common.collect.Lists
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.test.BasicBoxTest
import org.jetbrains.kotlin.js.test.JsIrTestRuntime
import org.jetbrains.kotlin.js.test.NashornJsTestChecker
import java.io.File
import javax.script.ScriptException
@@ -19,12 +20,13 @@ abstract class AbstractWebDemoExamplesTest(relativePath: String) : BasicBoxTest(
generateNodeJsRunner = false
) {
override fun runGeneratedCode(
jsFiles: List<String>,
testModuleName: String?,
testPackage: String?,
testFunction: String,
expectedResult: String,
withModuleSystem: Boolean
jsFiles: List<String>,
testModuleName: String?,
testPackage: String?,
testFunction: String,
expectedResult: String,
withModuleSystem: Boolean,
runtime: JsIrTestRuntime
) {
NashornJsTestChecker.checkStdout(jsFiles, expectedResult)
}
+26 -10
View File
@@ -14,29 +14,45 @@ if (cwd.endsWith(testDataPathFromRoot)) {
process.chdir(cwd.substr(0, cwd.length - testDataPathFromRoot.length));
}
var runtimeFiles = ["js/js.translator/testData/out/irBox/testRuntime.js"];
var filesFromArgs = process.argv.slice(2);
function toAbsolutePath(path) {
if (fs.existsSync(path) && fs.statSync(path).isFile()) {
return fs.realpathSync(path)
}
return "";
}
// TODO autodetect common js files and other js files
// Filter out all except existing js files and transform all paths to absolute
var files = [].concat(runtimeFiles, filesFromArgs, anotherFiles)
.map(function(path) {
if (fs.existsSync(path) && fs.statSync(path).isFile()) {
return fs.realpathSync(path)
}
return "";
})
var files = [].concat(filesFromArgs, anotherFiles)
.map(toAbsolutePath)
.filter(function(path) {
return path.endsWith(".js")
});
// Find runtime path
var runtimeHeader = "// RUNTIME: ";
var runtimeFiles = [];
files.forEach(function (path) {
var code = fs.readFileSync(path, 'utf8');
var firstLine = code.substr(0, code.indexOf("\n"));
if (firstLine.startsWith(runtimeHeader)) {
runtimeFiles = JSON.parse(firstLine.slice(runtimeHeader.length))
.map(toAbsolutePath);
}
});
var allFiles = [].concat(files, runtimeFiles);
// Evaluate files and run box function
var sandbox = {};
vm.createContext(sandbox);
files.forEach(function(path) {
allFiles.forEach(function(path) {
var code = fs.readFileSync(path, 'utf8');
vm.runInContext(code, sandbox, {
filename: path
+1
View File
@@ -6,4 +6,5 @@
package kotlin.io
// temporary for shared code, until we have an annotation like JvmSerializable
@Suppress("ACTUAL_WITHOUT_EXPECT")
internal actual interface Serializable