JS IR: support kotlin.test
This commit is contained in:
@@ -71,7 +71,11 @@ sourceSets {
|
||||
fun Test.setUpBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean) {
|
||||
dependsOn(":dist")
|
||||
if (jsEnabled) dependsOn(testJsRuntime)
|
||||
if (jsIrEnabled) dependsOn(":compiler:ir.serialization.js:generateIrRuntimeKlib")
|
||||
if (jsIrEnabled) {
|
||||
dependsOn(":compiler:ir.serialization.js:generateFullRuntimeKLib")
|
||||
dependsOn(":compiler:ir.serialization.js:generateReducedRuntimeKLib")
|
||||
dependsOn(":compiler:ir.serialization.js:generateKotlinTestKLib")
|
||||
}
|
||||
|
||||
if (jsEnabled && !jsIrEnabled) exclude("org/jetbrains/kotlin/js/test/ir/semantics/*")
|
||||
if (!jsEnabled && jsIrEnabled) include("org/jetbrains/kotlin/js/test/ir/semantics/*")
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderImpl
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
|
||||
import org.jetbrains.kotlin.incremental.js.TranslationResultValue
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrTestRuntime
|
||||
import org.jetbrains.kotlin.js.JavaScript
|
||||
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
@@ -110,11 +109,7 @@ 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 needsFullIrRuntime = KJS_WITH_FULL_RUNTIME.matcher(fileContent).find()
|
||||
|
||||
val actualMainCallParameters = if (CALL_MAIN_PATTERN.matcher(fileContent).find()) MainCallParameters.mainWithArguments(listOf("testArg")) else mainCallParameters
|
||||
|
||||
@@ -150,7 +145,7 @@ abstract class BasicBoxTest(
|
||||
file.parent, module, outputFileName, dependencies, allDependencies, friends, modules.size > 1,
|
||||
!SKIP_SOURCEMAP_REMAPPING.matcher(fileContent).find(),
|
||||
outputPrefixFile, outputPostfixFile, actualMainCallParameters, testPackage, testFunction,
|
||||
runtimeType, isMainModule
|
||||
needsFullIrRuntime, isMainModule
|
||||
)
|
||||
|
||||
when {
|
||||
@@ -333,7 +328,7 @@ abstract class BasicBoxTest(
|
||||
mainCallParameters: MainCallParameters,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime,
|
||||
needsFullIrRuntime: Boolean,
|
||||
isMainModule: Boolean
|
||||
) {
|
||||
val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") }
|
||||
@@ -356,13 +351,13 @@ abstract class BasicBoxTest(
|
||||
val incrementalData = IncrementalData()
|
||||
translateFiles(
|
||||
psiFiles.map(TranslationUnit::SourceFile), outputFile, config, outputPrefixFile, outputPostfixFile,
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime, isMainModule
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, isMainModule
|
||||
)
|
||||
|
||||
if (incrementalCompilationChecksEnabled && module.hasFilesToRecompile) {
|
||||
checkIncrementalCompilation(
|
||||
sourceDirs, module, kotlinFiles, dependencies, allDependencies, friends, multiModule, remap,
|
||||
outputFile, outputPrefixFile, outputPostfixFile, mainCallParameters, incrementalData, testPackage, testFunction, runtime
|
||||
outputFile, outputPrefixFile, outputPostfixFile, mainCallParameters, incrementalData, testPackage, testFunction, needsFullIrRuntime
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -383,7 +378,7 @@ abstract class BasicBoxTest(
|
||||
incrementalData: IncrementalData,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime
|
||||
needsFullIrRuntime: Boolean
|
||||
) {
|
||||
val sourceToTranslationUnit = hashMapOf<File, TranslationUnit>()
|
||||
for (testFile in kotlinFiles) {
|
||||
@@ -405,7 +400,7 @@ abstract class BasicBoxTest(
|
||||
|
||||
translateFiles(
|
||||
translationUnits, recompiledOutputFile, recompiledConfig, outputPrefixFile, outputPostfixFile,
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime, false
|
||||
mainCallParameters, incrementalData, remap, testPackage, testFunction, needsFullIrRuntime, false
|
||||
)
|
||||
|
||||
val originalOutput = FileUtil.loadFile(outputFile)
|
||||
@@ -470,7 +465,7 @@ abstract class BasicBoxTest(
|
||||
remap: Boolean,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime,
|
||||
needsFullIrRuntime: Boolean,
|
||||
isMainModule: Boolean
|
||||
) {
|
||||
val translator = K2JSTranslator(config, false)
|
||||
|
||||
@@ -7,7 +7,10 @@ package org.jetbrains.kotlin.js.test
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.KlibModuleRef
|
||||
import org.jetbrains.kotlin.ir.backend.js.compile
|
||||
import org.jetbrains.kotlin.ir.backend.js.generateKLib
|
||||
import org.jetbrains.kotlin.ir.backend.js.jsPhases
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||
@@ -15,13 +18,9 @@ import org.jetbrains.kotlin.js.facade.TranslationUnit
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
import java.io.File
|
||||
|
||||
private val fullRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeFull/"
|
||||
private val defaultRuntimeKlibPath = "js/js.translator/testData/out/klibs/runtimeDefault/"
|
||||
|
||||
private val JS_IR_RUNTIME_MODULE_NAME = "JS_IR_RUNTIME"
|
||||
|
||||
private val fullRuntimeKlib = KlibModuleRef(JS_IR_RUNTIME_MODULE_NAME, fullRuntimeKlibPath)
|
||||
private val defaultRuntimeKlib = KlibModuleRef(JS_IR_RUNTIME_MODULE_NAME, defaultRuntimeKlibPath)
|
||||
private val fullRuntimeKlib = KlibModuleRef("JS_IR_RUNTIME", "compiler/ir/serialization.js/build/fullRuntime/klib")
|
||||
private val defaultRuntimeKlib = KlibModuleRef("JS_IR_RUNTIME", "compiler/ir/serialization.js/build/reducedRuntime/klib")
|
||||
private val kotlinTestKLib = KlibModuleRef("kotlin.test", "compiler/ir/serialization.js/build/kotlin.test/klib")
|
||||
|
||||
abstract class BasicIrBoxTest(
|
||||
pathToTestDir: String,
|
||||
@@ -53,10 +52,6 @@ abstract class BasicIrBoxTest(
|
||||
|
||||
override val testChecker get() = if (runTestInNashorn) NashornIrJsTestChecker() else V8IrJsTestChecker
|
||||
|
||||
private val runtimes = mapOf(
|
||||
JsIrTestRuntime.DEFAULT to defaultRuntimeKlib,
|
||||
JsIrTestRuntime.FULL to fullRuntimeKlib)
|
||||
|
||||
override fun translateFiles(
|
||||
units: List<TranslationUnit>,
|
||||
outputFile: File,
|
||||
@@ -68,7 +63,7 @@ abstract class BasicIrBoxTest(
|
||||
remap: Boolean,
|
||||
testPackage: String?,
|
||||
testFunction: String,
|
||||
runtime: JsIrTestRuntime,
|
||||
needsFullIrRuntime: Boolean,
|
||||
isMainModule: Boolean
|
||||
) {
|
||||
val filesToCompile = units
|
||||
@@ -76,35 +71,20 @@ abstract class BasicIrBoxTest(
|
||||
// TODO: split input files to some parts (global common, local common, test)
|
||||
.filterNot { it.virtualFilePath.contains(BasicBoxTest.COMMON_FILES_DIR_PATH) }
|
||||
|
||||
// config.configuration.put(CommonConfigurationKeys.EXCLUDED_ELEMENTS_FROM_DUMPING, setOf("<JS_IR_RUNTIME>"))
|
||||
// config.configuration.put(
|
||||
// CommonConfigurationKeys.PHASES_TO_VALIDATE_AFTER,
|
||||
// setOf(
|
||||
// "RemoveInlineFunctionsWithReifiedTypeParametersLowering",
|
||||
// "InnerClassConstructorCallsLowering",
|
||||
// "InlineClassLowering", "ConstLowering"
|
||||
// )
|
||||
// )
|
||||
|
||||
val runtimeKlib = runtimes[runtime]!!
|
||||
val runtimeKlibs = if (needsFullIrRuntime) listOf(fullRuntimeKlib, kotlinTestKLib) else listOf(defaultRuntimeKlib)
|
||||
|
||||
val libraries = config.configuration[JSConfigurationKeys.LIBRARIES]!!.map { File(it).name }
|
||||
val transitiveLibraries = config.configuration[JSConfigurationKeys.TRANSITIVE_LIBRARIES]!!.map { File(it).name }
|
||||
|
||||
// TODO: Add proper depencencies
|
||||
val dependencies = listOf(runtimeKlib) + libraries.map {
|
||||
val dependencies = runtimeKlibs + libraries.map {
|
||||
compilationCache[it] ?: error("Can't find compiled module for dependency $it")
|
||||
}
|
||||
|
||||
val allDependencies = listOf(runtimeKlib) + transitiveLibraries.map {
|
||||
val allDependencies = runtimeKlibs + transitiveLibraries.map {
|
||||
compilationCache[it] ?: error("Can't find compiled module for dependency $it")
|
||||
}
|
||||
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE, setOf("UnitMaterializationLowering"))
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_BEFORE, setOf("ReturnableBlockLowering"))
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_AFTER, setOf("MultipleCatchesLowering"))
|
||||
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_VALIDATE, setOf("ALL"))
|
||||
|
||||
val actualOutputFile = outputFile.absolutePath.let {
|
||||
if (!isMainModule) it.replace("_v5.js", "/") else it
|
||||
}
|
||||
|
||||
+90
-23
@@ -1,44 +1,107 @@
|
||||
package common
|
||||
|
||||
import kotlin.test.FrameworkAdapter
|
||||
import kotlin.collections.*
|
||||
|
||||
private val context = TestContext()
|
||||
private var sortingContext = SortingContext()
|
||||
|
||||
fun call(name: String) = context.call(name)
|
||||
private var bodyContext: TestBodyContext? = null
|
||||
|
||||
fun call(name: String) = bodyContext!!.call(name)
|
||||
|
||||
fun raise(name: String): Nothing {
|
||||
context.raised(name)
|
||||
bodyContext!!.raised(name)
|
||||
throw Exception(name)
|
||||
}
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
val underscore = kotlin.test.setAdapter(object : FrameworkAdapter {
|
||||
private val underscore = kotlin.test.setAdapter(object : FrameworkAdapter {
|
||||
override fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) {
|
||||
context.suite(name, ignored) { suiteFn() }
|
||||
sortingContext.suite(name, ignored) { suiteFn() }
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, testFn: () -> dynamic) {
|
||||
context.test(name, ignored) { returned(testFn()) }
|
||||
sortingContext.test(name, ignored) { returned(testFn()) }
|
||||
}
|
||||
})
|
||||
|
||||
class TestContext {
|
||||
interface SuiteContext {
|
||||
fun suite(name: String, ignored: Boolean = false, body: SuiteContext.() -> Unit)
|
||||
|
||||
fun test(name: String, ignored: Boolean = false, body: TestBodyContext.() -> Unit = {})
|
||||
}
|
||||
|
||||
|
||||
interface TestBodyContext {
|
||||
fun call(name: String)
|
||||
|
||||
fun raised(msg: String)
|
||||
|
||||
fun caught(msg: String)
|
||||
|
||||
fun returned(msg: dynamic)
|
||||
}
|
||||
|
||||
private sealed class Entity(val name: String,
|
||||
val ignored: Boolean)
|
||||
|
||||
private class Suite(name: String, ignored: Boolean, val body: SuiteContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
private class Test(name: String, ignored: Boolean, val body: TestBodyContext.() -> Unit): Entity(name, ignored)
|
||||
|
||||
|
||||
private class SortingContext: SuiteContext {
|
||||
|
||||
val structure = mutableListOf<Entity>()
|
||||
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) {
|
||||
structure += Suite(name, ignored, body)
|
||||
}
|
||||
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) {
|
||||
structure += Test(name, ignored, body)
|
||||
}
|
||||
|
||||
fun <T: SuiteContext> replayInto(context: T): T {
|
||||
structure.sortedBy { it.name }.forEach {
|
||||
when (it) {
|
||||
is Suite -> context.suite(it.name, it.ignored) {
|
||||
val oldSorter = sortingContext
|
||||
|
||||
sortingContext = SortingContext()
|
||||
it.body(sortingContext)
|
||||
sortingContext.replayInto(this)
|
||||
|
||||
sortingContext = oldSorter
|
||||
}
|
||||
is Test -> context.test(it.name, it.ignored) {
|
||||
bodyContext = this
|
||||
it.body(this)
|
||||
bodyContext = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
private class LoggingContext : SuiteContext, TestBodyContext{
|
||||
val log: String
|
||||
get() = logHead + (lastRecord ?: "")
|
||||
|
||||
var indentation = ""
|
||||
private var indentation = ""
|
||||
|
||||
fun suite(name: String, ignored: Boolean = false, body: TestContext.() -> Unit) = indent {
|
||||
override fun suite(name: String, ignored: Boolean, body: SuiteContext.() -> Unit) = indent {
|
||||
record("suite(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
body.runSafely()
|
||||
runSafely { this.body() }
|
||||
record("}")
|
||||
}
|
||||
|
||||
|
||||
fun test(name: String, ignored: Boolean = false, body: TestContext.() -> Unit = {}) = indent {
|
||||
override fun test(name: String, ignored: Boolean, body: TestBodyContext.() -> Unit) = indent {
|
||||
val num = record("test(\"$name\"${optionalIgnore(ignored)}) {")
|
||||
|
||||
body.runSafely()
|
||||
runSafely { this.body() }
|
||||
|
||||
if (!writtenSince(num)) {
|
||||
record("test(\"$name\"${optionalIgnore(ignored)})", replaceLast = true)
|
||||
@@ -48,25 +111,25 @@ class TestContext {
|
||||
}
|
||||
}
|
||||
|
||||
fun call(name: String) = indent {
|
||||
override fun call(name: String) = indent {
|
||||
record("call(\"$name\")")
|
||||
}
|
||||
|
||||
fun raised(msg: String) = indent {
|
||||
override fun raised(msg: String) = indent {
|
||||
record("raised(\"$msg\")")
|
||||
}
|
||||
|
||||
fun caught(msg: String) = indent {
|
||||
override fun caught(msg: String) = indent {
|
||||
record("caught(\"$msg\")")
|
||||
}
|
||||
|
||||
fun returned(msg: dynamic) = indent {
|
||||
override fun returned(msg: dynamic) = indent {
|
||||
if (msg is String) record("returned(\"$msg\")")
|
||||
}
|
||||
|
||||
private fun (TestContext.() -> Unit).runSafely() {
|
||||
private fun runSafely(body: () -> Unit) {
|
||||
try {
|
||||
this()
|
||||
body()
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
caught(t.message ?: "")
|
||||
@@ -100,8 +163,8 @@ class TestContext {
|
||||
private fun optionalIgnore(ignored: Boolean) = if (ignored) ", true" else ""
|
||||
}
|
||||
|
||||
fun checkLog(wrapInEmptySuite: Boolean = true, body: TestContext.() -> Unit): String {
|
||||
val expectedContext = TestContext()
|
||||
fun checkLog(wrapInEmptySuite: Boolean = true, body: SuiteContext.() -> Unit): String {
|
||||
val expectedContext = SortingContext()
|
||||
if (wrapInEmptySuite) {
|
||||
expectedContext.suite("") {
|
||||
body()
|
||||
@@ -109,8 +172,12 @@ fun checkLog(wrapInEmptySuite: Boolean = true, body: TestContext.() -> Unit): St
|
||||
} else {
|
||||
expectedContext.body()
|
||||
}
|
||||
if (context.log != expectedContext.log) {
|
||||
return "Failed test structure check. Expected: ${expectedContext.log}; actual: ${context.log}."
|
||||
|
||||
val expectedLog = expectedContext.replayInto(LoggingContext()).log
|
||||
val actualLog = sortingContext.replayInto(LoggingContext()).log
|
||||
|
||||
if (actualLog != expectedLog) {
|
||||
return "Failed test structure check. Expected: ${expectedLog}; actual: ${actualLog}."
|
||||
}
|
||||
else {
|
||||
return "OK"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1339
|
||||
// EXPECTED_REACHABLE_NODES: 1706
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1340
|
||||
// EXPECTED_REACHABLE_NODES: 1709
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.Ignore
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1330
|
||||
// EXPECTED_REACHABLE_NODES: 1829
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
// FILE: a.kt
|
||||
package a
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1351
|
||||
// EXPECTED_REACHABLE_NODES: 1719
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1697
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// EXPECTED_REACHABLE_NODES: 1328
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
// FILE: lib.kt
|
||||
import kotlin.test.Test
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1367
|
||||
// EXPECTED_REACHABLE_NODES: 1735
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1297
|
||||
// EXPECTED_REACHABLE_NODES: 1737
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// EXPECTED_REACHABLE_NODES: 1330
|
||||
// EXPECTED_REACHABLE_NODES: 1698
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import common.*
|
||||
import kotlin.test.Test
|
||||
|
||||
|
||||
Reference in New Issue
Block a user