[JS TESTS] Rewrite js ir tests using new test infrastructure

This commit is contained in:
Ivan Kylchik
2021-10-25 18:22:33 +03:00
parent 0e4cf05d3e
commit c59098df2f
29 changed files with 9789 additions and 3981 deletions
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2021 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.test.services
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.library.KotlinLibrary
class JsLibraryProvider(private val testServices: TestServices) : TestService {
private val descriptorToLibrary = mutableMapOf<ModuleDescriptor, KotlinLibrary>()
private val stdlibPathToDescriptor = mutableMapOf<String, ModuleDescriptorImpl>()
fun getDescriptorByPath(path: String): ModuleDescriptorImpl {
return stdlibPathToDescriptor[path] ?: testServices.assertions.fail {
"There is no library with path $path"
}
}
fun setDescriptorAndLibraryByName(name: String, descriptor: ModuleDescriptorImpl, library: KotlinLibrary) {
stdlibPathToDescriptor[name] = descriptor
descriptorToLibrary[descriptor] = library
}
fun getCompiledLibraryByDescriptor(descriptor: ModuleDescriptor): KotlinLibrary {
return descriptorToLibrary[descriptor] ?: testServices.assertions.fail {
"There is no library for descriptor ${descriptor.name}"
}
}
fun getPathByDescriptor(descriptor: ModuleDescriptor): String {
return stdlibPathToDescriptor.entries.single { it.value == descriptor }.key
}
fun getDescriptorByCompiledLibrary(library: KotlinLibrary): ModuleDescriptor {
return descriptorToLibrary.filterValues { it == library }.keys.singleOrNull() ?: testServices.assertions.fail {
"There is no descriptor for library ${library.libraryName}"
}
}
fun getOrCreateStdlibByPath(path: String, create: (String) -> Pair<ModuleDescriptorImpl, KotlinLibrary>): ModuleDescriptorImpl {
return stdlibPathToDescriptor.getOrPut(path) {
create(path).let {
descriptorToLibrary += it
it.first
}
}
}
}
val TestServices.jsLibraryProvider: JsLibraryProvider by TestServices.testServiceAccessor()
@@ -103,3 +103,6 @@ val TestFile.isJavaFile: Boolean
val TestFile.isJsFile: Boolean
get() = name.endsWith(".js")
val TestFile.isMjsFile: Boolean
get() = name.endsWith(".mjs")
@@ -96,6 +96,11 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
applicability = DirectiveApplicability.Global
)
val SPLIT_PER_FILE by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val SKIP_MANGLE_VERIFICATION by directive(
description = "",
applicability = DirectiveApplicability.Global
@@ -183,6 +188,8 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
applicability = DirectiveApplicability.Global
)
// Directives for IR tests
val RUN_IR_DCE by directive(
description = "Enables dead code elimination on IR",
applicability = DirectiveApplicability.Global
@@ -192,4 +199,39 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
description = "Enables pir on IR", // TODO what `pir` stands for?
applicability = DirectiveApplicability.Global
)
val RUN_IC by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val LOWER_PER_MODULE by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val KLIB_MAIN_MODULE by directive(
description = "Specify that main module is actually a klib",
applicability = DirectiveApplicability.Global
)
val ES_MODULES by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val ENTRY_ES_MODULE by directive(
description = "",
applicability = DirectiveApplicability.File
)
val RUN_ES6_MODE by directive(
description = "",
applicability = DirectiveApplicability.Global
)
val PER_MODULE by directive(
description = "",
applicability = DirectiveApplicability.Global
)
}
@@ -10,15 +10,21 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.CodegenFactory
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.ir.backend.js.generateIrForKlibSerialization
import org.jetbrains.kotlin.ir.backend.js.sortDependencies
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.BackendKinds
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.*
class ClassicFrontend2IrConverter(
testServices: TestServices
@@ -27,10 +33,18 @@ class ClassicFrontend2IrConverter(
FrontendKinds.ClassicFrontend,
BackendKinds.IrBackend
) {
override fun transform(
module: TestModule,
inputArtifact: ClassicFrontendOutputArtifact
): IrBackendInput {
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::JsLibraryProvider))
override fun transform(module: TestModule, inputArtifact: ClassicFrontendOutputArtifact): IrBackendInput {
return when (module.targetBackend) {
TargetBackend.JVM_IR -> transformToJvmIr(module, inputArtifact)
TargetBackend.JS_IR -> transformToJsIr(module, inputArtifact)
else -> testServices.assertions.fail { "Target backend ${module.targetBackend} not supported for transformation into IR" }
}
}
private fun transformToJvmIr(module: TestModule, inputArtifact: ClassicFrontendOutputArtifact): IrBackendInput {
val (psiFiles, analysisResult, project, _) = inputArtifact
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
@@ -52,4 +66,36 @@ class ClassicFrontend2IrConverter(
codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationState(state))
)
}
private fun transformToJsIr(module: TestModule, inputArtifact: ClassicFrontendOutputArtifact): IrBackendInput {
val (psiFiles, analysisResult, project, _) = inputArtifact
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val verifySignatures = JsEnvironmentConfigurationDirectives.SKIP_MANGLE_VERIFICATION !in module.directives
val dependencies = testServices.moduleDescriptorProvider.getModuleDescriptor(module).allDependencyModules
val allDependencies = dependencies.associateBy { testServices.jsLibraryProvider.getCompiledLibraryByDescriptor(it) }
val expectDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
val moduleFragment = generateIrForKlibSerialization(
project,
psiFiles.values.toList(),
configuration,
analysisResult,
sortDependencies(allDependencies),
mutableListOf(),
expectDescriptorToSymbol,
IrFactoryImpl,
verifySignatures
) {
testServices.jsLibraryProvider.getDescriptorByCompiledLibrary(it)
}
return IrBackendInput.JsIrBackendInput(
moduleFragment,
psiFiles.values.toList(),
bindingContext = analysisResult.bindingContext,
expectDescriptorToSymbol = expectDescriptorToSymbol,
)
}
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JVMConfigurationKeys.JVM_TARGET
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.context.ProjectContext
@@ -30,7 +32,16 @@ import org.jetbrains.kotlin.frontend.java.di.initJvmBuiltInsForTopDownAnalysis
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.InlineConstTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.backend.js.JsFactories
import org.jetbrains.kotlin.ir.backend.js.TopDownAnalyzerFacadeForJSIR
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.toResolverLogger
import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.library.KLIB_PROPERTY_DEPENDS
import org.jetbrains.kotlin.library.unresolvedDependencies
import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.name.Name
@@ -49,7 +60,9 @@ import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.*
@@ -163,7 +176,10 @@ class ClassicFrontendFacade(
friendsDescriptors,
hasCommonModules
)
targetPlatform.isJs() -> performJsModuleResolve(project, configuration, files, dependentDescriptors)
targetPlatform.isJs() -> when {
module.targetBackend?.isIR != true -> performJsModuleResolve(project, configuration, files, dependentDescriptors)
else -> performJsIrModuleResolve(module, project, configuration, files, dependentDescriptors, friendsDescriptors)
}
targetPlatform.isNative() -> performNativeModuleResolve(module, project, files)
targetPlatform.isCommon() -> performCommonModuleResolve(module, files)
else -> error("Should not be here")
@@ -257,6 +273,77 @@ class ClassicFrontendFacade(
)
}
private fun loadKlib(names: List<String>, configuration: CompilerConfiguration): List<ModuleDescriptorImpl> {
val resolvedLibraries = jsResolveLibraries(
names,
configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(),
configuration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger()
).getFullResolvedList()
var builtInsModule: KotlinBuiltIns? = null
val dependencies = mutableListOf<ModuleDescriptorImpl>()
return resolvedLibraries.zip(names).map { (resolvedLibrary, klibPath) ->
testServices.jsLibraryProvider.getOrCreateStdlibByPath(klibPath) {
val storageManager = LockBasedStorageManager("ModulesStructure")
val isBuiltIns = resolvedLibrary.library.unresolvedDependencies.isEmpty()
val moduleDescriptor = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
resolvedLibrary.library,
configuration.languageVersionSettings,
storageManager,
builtInsModule,
packageAccessHandler = null,
lookupTracker = LookupTracker.DO_NOTHING
)
if (isBuiltIns) builtInsModule = moduleDescriptor.builtIns
dependencies += moduleDescriptor
moduleDescriptor.setDependencies(dependencies)
Pair(moduleDescriptor, resolvedLibrary.library)
}
}
}
@OptIn(ExperimentalStdlibApi::class)
private fun performJsIrModuleResolve(
module: TestModule,
project: Project,
configuration: CompilerConfiguration,
files: List<KtFile>,
dependentDescriptors: List<ModuleDescriptorImpl>,
friendsDescriptors: List<ModuleDescriptorImpl>,
): AnalysisResult {
// val jsConfig = JsEnvironmentConfigurator.createJsConfig(project, configuration)
val runtimeKlibsNames = JsEnvironmentConfigurator.getStdlibPathsForModule(module)
val runtimeKlibs = loadKlib(runtimeKlibsNames, configuration)
val transitiveLibraries = configuration[JSConfigurationKeys.TRANSITIVE_LIBRARIES]!!.map {
testServices.jsLibraryProvider.getDescriptorByPath(File(it).absolutePath.replace("_v5.meta.js", "").replace("outputDir", "outputKlibDir"))
}
val friendLibraries = configuration[JSConfigurationKeys.FRIEND_PATHS]!!.map {
testServices.jsLibraryProvider.getDescriptorByPath(File(it).absolutePath.replace("_v5.meta.js", "").replace("outputDir", "outputKlibDir"))
}
val allDependencies = runtimeKlibs + dependentDescriptors + transitiveLibraries
val analyzer = AnalyzerWithCompilerReport(configuration)
val builtInModuleDescriptor = allDependencies.firstNotNullOfOrNull { it.builtIns }?.builtInsModule
analyzer.analyzeAndReport(files) {
TopDownAnalyzerFacadeForJSIR.analyzeFiles(
files,
project,
configuration,
allDependencies,
friendsDescriptors + friendLibraries,
CompilerEnvironment,
thisIsBuiltInsModule = builtInModuleDescriptor == null,
customBuiltInsModule = builtInModuleDescriptor
)
}
return analyzer.analysisResult
}
private fun performNativeModuleResolve(
module: TestModule,
project: Project,
@@ -6,9 +6,12 @@
package org.jetbrains.kotlin.test.model
import org.jetbrains.kotlin.codegen.ClassFileFactory
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.incremental.js.TranslationResultValue
import org.jetbrains.kotlin.ir.backend.js.CompilerResult
import org.jetbrains.kotlin.js.backend.ast.JsProgram
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.ir.backend.js.LoweredIr
import org.jetbrains.kotlin.js.facade.TranslationResult
import java.io.File
@@ -26,8 +29,13 @@ object BinaryArtifacts {
open fun unwrap(): Js = this
class OldJsArtifact(override val outputFile: File, val translationResult: TranslationResult) : Js()
class JsIrArtifact(override val outputFile: File, val compilerResult: CompilerResult) : Js()
class JsKlibArtifact(override val outputFile: File, val descriptor: ModuleDescriptor, val library: KotlinLibrary) : Js()
class JsEsArtifact(override val outputFile: File, val outputDceFile: File?) : Js()
data class IncrementalJsArtifact(val originalArtifact: Js, val recompiledArtifact: Js) : Js() {
override val outputFile: File
get() = unwrap().outputFile
@@ -6,14 +6,18 @@
package org.jetbrains.kotlin.test.services.configuration
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.js.config.*
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.jetbrains.kotlin.serialization.js.JsModuleDescriptor
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.MODULE_KIND
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.NO_INLINE
@@ -39,6 +43,7 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
const val OLD_MODULE_SUFFIX = "_old"
private const val OUTPUT_DIR_NAME = "outputDir"
private const val OUTPUT_KLIB_DIR_NAME = "outputKlibDir"
private const val DCE_OUTPUT_DIR_NAME = "dceOutputDir"
private const val PIR_OUTPUT_DIR_NAME = "pirOutputDir"
private const val MINIFICATION_OUTPUT_DIR_NAME = "minOutputDir"
@@ -66,10 +71,26 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
return getJsArtifactsOutputDir(testServices).absolutePath + "/" + getJsArtifactSimpleName(testServices, moduleName) + "_v5"
}
fun getJsKlibArtifactPath(testServices: TestServices, moduleName: String): String {
return getJsKlibOutputDir(testServices).absolutePath + "/" + getJsArtifactSimpleName(testServices, moduleName)
}
fun getDceJsArtifactPath(testServices: TestServices, moduleName: String): String {
return getDceJsArtifactsOutputDir(testServices).absolutePath + "/" + getJsArtifactSimpleName(testServices, moduleName) + "_v5"
}
fun getPirJsArtifactPath(testServices: TestServices, moduleName: String): String {
return getPirJsArtifactsOutputDir(testServices).absolutePath + "/" + getJsArtifactSimpleName(testServices, moduleName) + "_v5"
}
fun getJsArtifactsOutputDir(testServices: TestServices): File {
return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(OUTPUT_DIR_NAME)
}
fun getJsKlibOutputDir(testServices: TestServices): File {
return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(OUTPUT_KLIB_DIR_NAME)
}
fun getDceJsArtifactsOutputDir(testServices: TestServices): File {
return testServices.temporaryDirectoryManager.getOrCreateTempDirectory(DCE_OUTPUT_DIR_NAME)
}
@@ -98,6 +119,39 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
project, configuration, CompilerEnvironment, METADATA_CACHE, (JsConfig.JS_STDLIB + JsConfig.JS_KOTLIN_TEST).toSet()
)
}
fun getMainModule(testServices: TestServices): TestModule {
val modules = testServices.moduleStructure.modules
val inferMainModule = JsEnvironmentConfigurationDirectives.INFER_MAIN_MODULE in testServices.moduleStructure.allDirectives
return when {
inferMainModule -> modules.last()
else -> modules.singleOrNull { it.name == ModuleStructureExtractor.DEFAULT_MODULE_NAME } ?: modules.single()
}
}
fun isMainModule(module: TestModule, testServices: TestServices): Boolean {
return module == getMainModule(testServices)
}
fun getMainModuleName(testServices: TestServices): String {
return getMainModule(testServices).name
}
fun getStdlibPathsForModule(module: TestModule): List<String> {
val needsFullIrRuntime = JsEnvironmentConfigurationDirectives.KJS_WITH_FULL_RUNTIME in module.directives ||
ConfigurationDirectives.WITH_STDLIB in module.directives ||
ConfigurationDirectives.WITH_RUNTIME in module.directives
val names = if (needsFullIrRuntime) listOf("full.stdlib", "kotlin.test") else listOf("reduced.stdlib")
return names.map { System.getProperty("kotlin.js.$it.path") }
}
fun getMainCallParametersForModule(module: TestModule): MainCallParameters {
return when (JsEnvironmentConfigurationDirectives.CALL_MAIN) {
in module.directives -> MainCallParameters.mainWithArguments(listOf())
else -> MainCallParameters.noCall()
}
}
}
@@ -111,7 +165,8 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
val registeredDirectives = module.directives
val moduleKinds = registeredDirectives[MODULE_KIND]
val moduleKind = when (moduleKinds.size) {
0 -> testServices.moduleStructure.allDirectives[MODULE_KIND].singleOrNull() ?: ModuleKind.PLAIN
0 -> testServices.moduleStructure.allDirectives[MODULE_KIND].singleOrNull()
?: if (JsEnvironmentConfigurationDirectives.ES_MODULES in registeredDirectives) ModuleKind.ES else ModuleKind.PLAIN
1 -> moduleKinds.single()
else -> error("Too many module kinds passed ${moduleKinds.joinToArrayString()}")
}
@@ -143,6 +198,9 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
if (errorIgnorancePolicy.allowErrors) {
configuration.put(JSConfigurationKeys.DEVELOPER_MODE, true)
}
if (errorIgnorancePolicy != ErrorTolerancePolicy.DEFAULT) {
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
}
val multiModule = testServices.moduleStructure.modules.size > 1
configuration.put(JSConfigurationKeys.META_INFO, multiModule)
@@ -160,10 +218,7 @@ class JsEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigu
configuration.put(
JSConfigurationKeys.FILE_PATHS_PREFIX_MAP,
mapOf(
// tmpDir.absolutePath to "<TMP>", // TODO check do we need this on js ir tests
File(".").absolutePath.removeSuffix(".") to ""
)
mapOf(File(".").absolutePath.removeSuffix(".") to "")
)
configuration.put(CommonConfigurationKeys.EXPECT_ACTUAL_LINKER, EXPECT_ACTUAL_LINKER in registeredDirectives)
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.test.generators
import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
import org.jetbrains.kotlin.js.testNew.*
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.runners.*
import org.jetbrains.kotlin.test.runners.codegen.*
+6 -2
View File
@@ -288,9 +288,11 @@ projectTest("jsTest", parallel = true, jUnitMode = JUnitMode.Mix) {
useJUnitPlatform()
}
projectTest("jsIrTest", true) {
projectTest("jsIrTest", true, jUnitMode = JUnitMode.JUnit5) {
systemProperty("kotlin.js.ir.pir", "false")
setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true)
maxHeapSize = "3g"
useJUnitPlatform()
}
projectTest("jsEs6IrTest", true) {
@@ -315,9 +317,11 @@ projectTest("jsEs6IrTest", true) {
setUpBoxTests()
}
projectTest("jsPirTest", true) {
projectTest("jsPirTest", parallel = true, jUnitMode = JUnitMode.JUnit5) {
systemProperty("kotlin.js.ir.skipRegularMode", "true")
setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true)
maxHeapSize = "3g"
useJUnitPlatform()
}
projectTest("quickTest", parallel = true, jUnitMode = JUnitMode.Mix) {
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.js.test.wasm.semantics.AbstractIrCodegenBoxWasmTest
import org.jetbrains.kotlin.js.test.wasm.semantics.AbstractIrCodegenWasmJsInteropWasmTest
import org.jetbrains.kotlin.js.test.wasm.semantics.AbstractJsTranslatorWasmTest
import org.jetbrains.kotlin.js.testNew.*
import org.jetbrains.kotlin.js.testNew.AbstractWebDemoExamplesTest
import org.jetbrains.kotlin.test.TargetBackend
fun main(args: Array<String>) {
@@ -36,10 +35,6 @@ fun main(args: Array<String>) {
generateTestGroupSuite(args) {
testGroup("js/js.tests/tests-gen", "js/js.translator/testData", testRunnerMethodName = "runTest0") {
testClass<AbstractIrBoxJsTest> {
model("box/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS_IR)
}
testClass<AbstractJsTranslatorWasmTest> {
model("box/main", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.WASM)
model("box/kotlin.test/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.WASM)
@@ -67,14 +62,6 @@ fun main(args: Array<String>) {
}
testGroup("js/js.tests/tests-gen", "compiler/testData", testRunnerMethodName = "runTest0") {
testClass<AbstractIrJsCodegenBoxTest> {
model("codegen/box", targetBackend = TargetBackend.JS_IR, excludeDirs = jvmOnlyBoxTests + "compileKotlinAgainstKotlin")
}
testClass<AbstractIrJsCodegenBoxErrorTest> {
model("codegen/boxError", targetBackend = TargetBackend.JS_IR, excludeDirs = jvmOnlyBoxTests + "compileKotlinAgainstKotlin")
}
testClass<AbstractIrCodegenBoxWasmTest> {
model(
"codegen/box", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.WASM, excludeDirs = listOf(
@@ -108,10 +95,6 @@ fun main(args: Array<String>) {
model("codegen/box", targetBackend = TargetBackend.JS_IR_ES6, excludeDirs = jvmOnlyBoxTests)
}
testClass<AbstractIrJsCodegenInlineTest> {
model("codegen/boxInline/", targetBackend = TargetBackend.JS_IR)
}
testClass<AbstractIrJsCodegenInlineES6Test> {
model("codegen/boxInline/", targetBackend = TargetBackend.JS_IR_ES6)
}
@@ -145,6 +128,10 @@ fun main(args: Array<String>) {
testClass<AbstractWebDemoExamplesTest> {
model("webDemoExamples/")
}
testClass<AbstractIrBoxJsTest> {
model("box/", pattern = "^([^_](.+))\\.kt$")
}
}
testGroup("js/js.tests/tests-gen", "compiler/testData", testRunnerMethodName = "runTest0") {
@@ -159,6 +146,18 @@ fun main(args: Array<String>) {
testClass<AbstractJsLegacyPrimitiveArraysBoxTest> {
model("codegen/box/arrays")
}
testClass<AbstractIrJsCodegenBoxTest> {
model("codegen/box", excludeDirs = jvmOnlyBoxTests + "compileKotlinAgainstKotlin")
}
testClass<AbstractIrJsCodegenBoxErrorTest> {
model("codegen/boxError", excludeDirs = jvmOnlyBoxTests + "compileKotlinAgainstKotlin")
}
testClass<AbstractIrJsCodegenInlineTest> {
model("codegen/boxInline")
}
}
}
}
@@ -462,9 +462,9 @@ abstract class BasicIrBoxTest(
dtsFile.write(compiledModule.tsDefinitions ?: error("No ts definitions"))
}
compiledOutput.jsProgram?.let {
JsAstHandler.processUnitsOfJsProgram(it, units, targetBackend = TargetBackend.JS_IR) { Assert.fail(it) }
}
compiledOutput.jsProgram?.let {
JsAstHandler.processUnitsOfJsProgram(it, units, targetBackend = TargetBackend.JS_IR) { Assert.fail(it) }
}
}
private fun generateTestFile(outputDir: File, config: JsConfig, customTestModule: String?) {
@@ -7,24 +7,6 @@ package org.jetbrains.kotlin.js.test.ir.semantics
import org.jetbrains.kotlin.js.test.BasicIrBoxTest
abstract class AbstractIrBoxJsTest : BasicIrBoxTest(TEST_DATA_DIR_PATH + "box/", "irBox/")
abstract class AbstractIrJsCodegenBoxTest : BasicIrBoxTest(
"compiler/testData/codegen/box/",
"codegen/irBox/"
)
abstract class AbstractIrJsCodegenBoxErrorTest : BasicIrBoxTest(
"compiler/testData/codegen/boxError/",
"codegen/irBoxError/"
)
abstract class AbstractIrJsCodegenInlineTest : BasicIrBoxTest(
"compiler/testData/codegen/boxInline/",
"codegen/irBoxInline/"
)
abstract class AbstractIrCodegenWasmJsInteropJsTest : BasicIrBoxTest(
"compiler/testData/codegen/wasmJsInterop",
"codegen/wasmJsInteropJs"
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHan
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest
import org.jetbrains.kotlin.test.runners.codegen.commonClassicFrontendHandlersForCodegenTest
import org.jetbrains.kotlin.test.services.JsLibraryProvider
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider
@@ -35,7 +36,8 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
abstract val frontendFacade: Constructor<FrontendFacade<R>>
abstract val frontendToBackendConverter: Constructor<Frontend2BackendConverter<R, I>>
abstract val backendFacade: Constructor<BackendFacade<I, BinaryArtifacts.Js>>
abstract val recompileFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>
abstract val afterBackendFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>?
abstract val recompileFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>?
override fun TestConfigurationBuilder.configuration() {
globalDefaults {
@@ -52,6 +54,7 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
+JsEnvironmentConfigurationDirectives.TYPED_ARRAYS
+JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER
if (skipMinification) +JsEnvironmentConfigurationDirectives.SKIP_MINIFICATION
if (getBoolean("kotlin.js.ir.skipRegularMode")) +JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE
}
useConfigurators(
@@ -65,6 +68,8 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
::CoroutineHelpersSourceFilesProvider,
)
useAdditionalService(::JsLibraryProvider)
useAfterAnalysisCheckers(
::JsFailingTestSuppressor,
::BlackBoxCodegenSuppressor,
@@ -80,7 +85,8 @@ abstract class AbstractJsBlackBoxCodegenTestBase<R : ResultingArtifact.FrontendO
irHandlersStep()
facadeStep(backendFacade)
facadeStep(recompileFacade)
afterBackendFacade?.let { facadeStep(it) }
recompileFacade?.let { facadeStep(it) }
jsArtifactsHandlersStep {
useHandlers(
::JsBoxRunner,
@@ -0,0 +1,98 @@
/*
* Copyright 2010-2021 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.js.testNew
import org.jetbrains.kotlin.js.testNew.converters.JsIrBackendFacade
import org.jetbrains.kotlin.js.testNew.converters.JsKlibBackendFacade
import org.jetbrains.kotlin.js.testNew.handlers.*
import org.jetbrains.kotlin.parsing.parseBoolean
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.backend.classic.ClassicBackendInput
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.configureJsArtifactsHandlersStep
import org.jetbrains.kotlin.test.builders.jsArtifactsHandlersStep
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontend2IrConverter
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.lang.Boolean.getBoolean
abstract class AbstractJsIrTest(
pathToTestDir: String,
testGroupOutputDirPrefix: String,
) : AbstractJsBlackBoxCodegenTestBase<ClassicFrontendOutputArtifact, IrBackendInput>(
FrontendKinds.ClassicFrontend, TargetBackend.JS_IR, pathToTestDir, testGroupOutputDirPrefix, skipMinification = true
) {
override val frontendFacade: Constructor<FrontendFacade<ClassicFrontendOutputArtifact>>
get() = ::ClassicFrontendFacade
override val frontendToBackendConverter: Constructor<Frontend2BackendConverter<ClassicFrontendOutputArtifact, IrBackendInput>>
get() = ::ClassicFrontend2IrConverter
override val backendFacade: Constructor<BackendFacade<IrBackendInput, BinaryArtifacts.Js>>
get() = ::JsKlibBackendFacade
override val afterBackendFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>?
get() = ::JsIrBackendFacade
override val recompileFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>?
get() = null
private fun getBoolean(s: String, default: Boolean) = System.getProperty(s)?.let { parseBoolean(it) } ?: default
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
with(builder) {
defaultDirectives {
val runIc = getBoolean("kotlin.js.ir.icMode")
val lowerPerModule = runIc || getBoolean("kotlin.js.ir.lowerPerModule")
if (runIc) +JsEnvironmentConfigurationDirectives.RUN_IC
if (lowerPerModule) +JsEnvironmentConfigurationDirectives.LOWER_PER_MODULE
if (getBoolean("kotlin.js.ir.klibMainModule")) +JsEnvironmentConfigurationDirectives.KLIB_MAIN_MODULE
if (getBoolean("kotlin.js.ir.es6")) +JsEnvironmentConfigurationDirectives.RUN_ES6_MODE
if (getBoolean("kotlin.js.ir.perModule")) +JsEnvironmentConfigurationDirectives.PER_MODULE
if (getBoolean("kotlin.js.ir.dce", true)) +JsEnvironmentConfigurationDirectives.RUN_IR_DCE
if (!lowerPerModule && getBoolean("kotlin.js.ir.pir", true)) +JsEnvironmentConfigurationDirectives.RUN_IR_PIR
}
configureJsArtifactsHandlersStep {
useHandlers(
::JsIrArtifactsDumpHandler,
::JsAstHandler,
::JsBoxRunner,
::NodeJsGeneratorHandler,
::JsMinifierRunner,
::JsArtifactsDumpHandler,
)
}
}
}
}
open class AbstractIrBoxJsTest : AbstractJsIrTest(
pathToTestDir = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/box/",
testGroupOutputDirPrefix = "box/"
)
open class AbstractIrJsCodegenBoxTest : AbstractJsIrTest(
pathToTestDir = "compiler/testData/codegen/box/",
testGroupOutputDirPrefix = "codegen/irBox/"
)
open class AbstractIrJsCodegenBoxErrorTest : AbstractJsIrTest(
pathToTestDir = "compiler/testData/codegen/boxError/",
testGroupOutputDirPrefix = "codegen/irBoxError/"
)
open class AbstractIrJsCodegenInlineTest : AbstractJsIrTest(
pathToTestDir = "compiler/testData/codegen/boxInline/",
testGroupOutputDirPrefix = "codegen/irBoxInline/"
)
@@ -35,6 +35,9 @@ abstract class AbstractJsTest(
override val backendFacade: Constructor<BackendFacade<ClassicBackendInput, BinaryArtifacts.Js>>
get() = ::ClassicJsBackendFacade
override val afterBackendFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>?
get() = null
override val recompileFacade: Constructor<AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>>
get() = { RecompileModuleJsBackendFacade(it, frontendFacade, frontendToBackendConverter) }
@@ -38,6 +38,25 @@ class ClassicJsBackendFacade(
) : ClassicBackendFacade<BinaryArtifacts.Js>(testServices, ArtifactKinds.Js) {
companion object {
const val KOTLIN_TEST_INTERNAL = "\$kotlin_test_internal\$"
fun wrapWithModuleEmulationMarkers(content: String, moduleKind: ModuleKind, moduleId: String): String {
val escapedModuleId = StringUtil.escapeStringCharacters(moduleId)
return when (moduleKind) {
ModuleKind.COMMON_JS -> "$KOTLIN_TEST_INTERNAL.beginModule();\n" +
"$content\n" +
"$KOTLIN_TEST_INTERNAL.endModule(\"$escapedModuleId\");"
ModuleKind.AMD, ModuleKind.UMD ->
"if (typeof $KOTLIN_TEST_INTERNAL !== \"undefined\") { " +
"$KOTLIN_TEST_INTERNAL.setModuleId(\"$escapedModuleId\"); }\n" +
"$content\n"
ModuleKind.PLAIN -> content
ModuleKind.ES -> error("Module emulation markers are not supported for ES modules")
}
}
}
constructor(testServices: TestServices) : this(testServices, incrementalCompilationEnabled = false)
@@ -45,25 +64,6 @@ class ClassicJsBackendFacade(
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::JsClassicIncrementalDataProvider))
private fun wrapWithModuleEmulationMarkers(content: String, moduleKind: ModuleKind, moduleId: String): String {
val escapedModuleId = StringUtil.escapeStringCharacters(moduleId)
return when (moduleKind) {
ModuleKind.COMMON_JS -> "$KOTLIN_TEST_INTERNAL.beginModule();\n" +
"$content\n" +
"$KOTLIN_TEST_INTERNAL.endModule(\"$escapedModuleId\");"
ModuleKind.AMD, ModuleKind.UMD ->
"if (typeof $KOTLIN_TEST_INTERNAL !== \"undefined\") { " +
"$KOTLIN_TEST_INTERNAL.setModuleId(\"$escapedModuleId\"); }\n" +
"$content\n"
ModuleKind.PLAIN -> content
ModuleKind.ES -> error("Module emulation markers are not supported for ES modules")
}
}
override fun transform(module: TestModule, inputArtifact: ClassicBackendInput): BinaryArtifacts.Js {
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val (psiFiles, analysisResult, project, _) = inputArtifact
@@ -0,0 +1,241 @@
/*
* Copyright 2010-2021 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.js.testNew.converters
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.codegen.CompilerOutputSink
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationOptions
import org.jetbrains.kotlin.ir.backend.js.codegen.generateEsModules
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.test.esModulesSubDir
import org.jetbrains.kotlin.js.testNew.handlers.JsBoxRunner.Companion.TEST_FUNCTION
import org.jetbrains.kotlin.js.testNew.utils.extractTestPackage
import org.jetbrains.kotlin.library.uniqueName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.jsLibraryProvider
import java.io.File
class JsIrBackendFacade(
val testServices: TestServices
) : AbstractTestFacade<BinaryArtifacts.Js, BinaryArtifacts.Js>() {
override val inputKind: ArtifactKinds.Js
get() = ArtifactKinds.Js
override val outputKind: ArtifactKinds.Js
get() = ArtifactKinds.Js
override fun transform(module: TestModule, inputArtifact: BinaryArtifacts.Js): BinaryArtifacts.Js? {
if (inputArtifact !is BinaryArtifacts.Js.JsKlibArtifact) {
error("JsIrBackendFacade expects BinaryArtifacts.Js.JsKlibArtifact as input")
}
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val isMainModule = JsEnvironmentConfigurator.isMainModule(module, testServices)
if (!isMainModule) return inputArtifact
val moduleInfo = loadIrFromKlib(module, configuration, inputArtifact)
return compileIrToJs(module, moduleInfo, configuration, inputArtifact)
}
private fun compileIrToJs(
module: TestModule,
moduleInfo: IrModuleInfo,
configuration: CompilerConfiguration,
inputArtifact: BinaryArtifacts.Js,
): BinaryArtifacts.Js? {
val (irModuleFragment, dependencyModules, _, symbolTable, deserializer, _) = moduleInfo
val generateDts = false // TODO
val splitPerModule = JsEnvironmentConfigurationDirectives.SPLIT_PER_MODULE in module.directives
val splitPerFile = JsEnvironmentConfigurationDirectives.SPLIT_PER_FILE in module.directives
val perModule = JsEnvironmentConfigurationDirectives.PER_MODULE in module.directives
val granularity = when {
splitPerModule || perModule -> JsGenerationGranularity.PER_MODULE
splitPerFile -> JsGenerationGranularity.PER_FILE
else -> JsGenerationGranularity.WHOLE_PROGRAM
}
val testPackage = extractTestPackage(testServices)
val mainArguments = JsEnvironmentConfigurator.getMainCallParametersForModule(module)
.run { if (shouldBeGenerated()) arguments() else null }
val lowerPerModule = JsEnvironmentConfigurationDirectives.LOWER_PER_MODULE in module.directives
val runIrPir = JsEnvironmentConfigurationDirectives.RUN_IR_PIR in module.directives &&
JsEnvironmentConfigurationDirectives.SKIP_DCE_DRIVEN !in module.directives
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in module.directives
val skipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE in module.directives
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in module.directives
if (skipRegularMode && !runIrPir) return null
val loweredIr = compileIr(
irModuleFragment,
MainModule.Klib(inputArtifact.outputFile.absolutePath),
configuration,
dependencyModules,
irModuleFragment.irBuiltins,
symbolTable,
deserializer,
PhaseConfig(jsPhases), // TODO debug mode
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))),
dceDriven = runIrPir,
dceRuntimeDiagnostic = null,
es6mode = JsEnvironmentConfigurationDirectives.RUN_ES6_MODE in module.directives,
propertyLazyInitialization = JsEnvironmentConfigurationDirectives.PROPERTY_LAZY_INITIALIZATION in module.directives,
baseClassIntoMetadata = false,
lowerPerModule = lowerPerModule,
safeExternalBoolean = JsEnvironmentConfigurationDirectives.SAFE_EXTERNAL_BOOLEAN in module.directives,
safeExternalBooleanDiagnostic = module.directives[JsEnvironmentConfigurationDirectives.SAFE_EXTERNAL_BOOLEAN_DIAGNOSTIC].singleOrNull(),
granularity = granularity
)
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js")
val dceOutputFile = File(JsEnvironmentConfigurator.getDceJsArtifactPath(testServices, module.name) + ".js")
val pirOutputFile = File(JsEnvironmentConfigurator.getPirJsArtifactPath(testServices, module.name) + ".js")
val dontSkipDceDriven = JsEnvironmentConfigurationDirectives.SKIP_DCE_DRIVEN !in module.directives
if (!esModules) {
val transformer = IrModuleToJsTransformer(
loweredIr.context,
mainArguments,
fullJs = true,
dceJs = if (runIrPir && dontSkipDceDriven) false else runIrDce,
multiModule = granularity == JsGenerationGranularity.PER_MODULE,
relativeRequirePath = false
)
return BinaryArtifacts.Js.JsIrArtifact(outputFile, transformer.generateModule(loweredIr.allModules))
}
val options = JsGenerationOptions(generatePackageJson = true, generateTypeScriptDefinitions = generateDts)
if (dontSkipDceDriven) {
generateEsModules(loweredIr, jsOutputSink(outputFile.parentFile.esModulesSubDir), mainArguments, granularity, options)
if (runIrDce) {
eliminateDeadDeclarations(loweredIr.allModules, loweredIr.context)
generateEsModules(loweredIr, jsOutputSink(dceOutputFile.parentFile.esModulesSubDir), mainArguments, granularity, options)
return BinaryArtifacts.Js.JsEsArtifact(outputFile, dceOutputFile)
}
return BinaryArtifacts.Js.JsEsArtifact(outputFile, null)
}
if (runIrPir && dontSkipDceDriven) {
generateEsModules(loweredIr, jsOutputSink(pirOutputFile.parentFile.esModulesSubDir), mainArguments, granularity, options)
return BinaryArtifacts.Js.JsEsArtifact(pirOutputFile, null)
}
return null
}
private fun loadIrFromKlib(
module: TestModule,
configuration: CompilerConfiguration,
inputArtifact: BinaryArtifacts.Js.JsKlibArtifact
): IrModuleInfo {
val dependencies = testServices.moduleDescriptorProvider.getModuleDescriptor(module).allDependencyModules
val allDependencies = dependencies.associateBy { testServices.jsLibraryProvider.getCompiledLibraryByDescriptor(it) }
val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None
val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl)
val mainModuleLib = inputArtifact.library
val moduleDescriptor = inputArtifact.descriptor
val friendLibraries = configuration[JSConfigurationKeys.FRIEND_PATHS]!!.map {
val descriptor = testServices.jsLibraryProvider.getDescriptorByPath(
File(it).absolutePath
.replace("_v5.meta.js", "")
.replace("outputDir", "outputKlibDir")
)
testServices.jsLibraryProvider.getCompiledLibraryByDescriptor(descriptor)
}
val friendModules = mapOf(mainModuleLib.uniqueName to friendLibraries.map { it.uniqueName })
return getIrModuleInfoForKlib(
moduleDescriptor,
sortDependencies(allDependencies) + mainModuleLib,
friendModules,
null,
configuration,
symbolTable,
messageLogger,
loadFunctionInterfacesIntoStdlib = true,
emptyMap(),
{ emptySet() },
{ if (it == mainModuleLib) moduleDescriptor else testServices.jsLibraryProvider.getDescriptorByCompiledLibrary(it) },
)
}
private fun loadIrFromSources(
module: TestModule,
configuration: CompilerConfiguration,
inputArtifact: ClassicFrontendOutputArtifact
): IrModuleInfo {
val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT
val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None
val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl)
val verifySignatures = JsEnvironmentConfigurationDirectives.SKIP_MANGLE_VERIFICATION !in module.directives
val dependencies = testServices.moduleDescriptorProvider.getModuleDescriptor(module).allDependencyModules
val allDependencies = dependencies.associateBy { testServices.jsLibraryProvider.getCompiledLibraryByDescriptor(it) }
val psi2Ir = Psi2IrTranslator(
configuration.languageVersionSettings,
Psi2IrConfiguration(errorPolicy.allowErrors)
)
val psi2IrContext = psi2Ir.createGeneratorContext(
inputArtifact.analysisResult.moduleDescriptor,
inputArtifact.analysisResult.bindingContext,
symbolTable
)
return getIrModuleInfoForSourceFiles(
psi2IrContext,
inputArtifact.project,
configuration,
inputArtifact.allKtFiles.values.toList(),
sortDependencies(allDependencies),
emptyMap(),
emptyMap(),
symbolTable,
messageLogger,
loadFunctionInterfacesIntoStdlib = true,
verifySignatures,
{ emptySet() },
{ testServices.jsLibraryProvider.getDescriptorByCompiledLibrary(it) },
)
}
private fun jsOutputSink(perFileOutputDir: File): CompilerOutputSink {
perFileOutputDir.deleteRecursively()
perFileOutputDir.mkdirs()
return object : CompilerOutputSink {
override fun write(module: String, path: String, content: String) {
val file = File(File(perFileOutputDir, module), path)
file.parentFile.mkdirs()
file.writeText(content)
}
}
}
override fun shouldRunAnalysis(module: TestModule): Boolean {
return JsEnvironmentConfigurator.isMainModule(module, testServices)
}
}
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2021 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.js.testNew.converters
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.codegen.CompilerOutputSink
import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.library.KotlinAbiVersion
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.test.backend.ir.IrBackendFacade
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
import org.jetbrains.kotlin.test.model.ArtifactKinds
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.jsLibraryProvider
import java.io.File
class JsKlibBackendFacade(
testServices: TestServices
) : IrBackendFacade<BinaryArtifacts.Js>(testServices, ArtifactKinds.Js) {
override fun transform(module: TestModule, inputArtifact: IrBackendInput): BinaryArtifacts.Js {
if (inputArtifact !is IrBackendInput.JsIrBackendInput) {
error("JsIrBackendFacade expects IrBackendInput.JsIrBackendInput as input")
}
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val project = testServices.compilerConfigurationProvider.getProject(module)
val outputFile = JsEnvironmentConfigurator.getJsKlibArtifactPath(testServices, module.name)
val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT
val hasErrors = TopDownAnalyzerFacadeForJSIR.checkForErrors(inputArtifact.sourceFiles, inputArtifact.bindingContext, errorPolicy)
val dependencies = testServices.moduleDescriptorProvider.getModuleDescriptor(module).allDependencyModules.map { it as ModuleDescriptorImpl }
val allDependencies = dependencies.map { testServices.jsLibraryProvider.getCompiledLibraryByDescriptor(it) }
serializeModuleIntoKlib(
configuration[CommonConfigurationKeys.MODULE_NAME]!!,
project,
configuration,
configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None,
inputArtifact.bindingContext,
inputArtifact.sourceFiles,
klibPath = outputFile,
allDependencies,
inputArtifact.irModuleFragment,
inputArtifact.expectDescriptorToSymbol,
cleanFiles = emptyList(),
nopack = true,
perFile = false,
containsErrorCode = hasErrors,
abiVersion = KotlinAbiVersion.CURRENT, // TODO get from test file data
jsOutputName = null
)
val lib = jsResolveLibraries(
dependencies.map { testServices.jsLibraryProvider.getPathByDescriptor(it) } + listOf(outputFile),
configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(),
configuration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger()
).getFullResolvedList().last().library
val moduleDescriptor = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
lib,
configuration.languageVersionSettings,
LockBasedStorageManager("ModulesStructure"),
testServices.moduleDescriptorProvider.getModuleDescriptor(module).builtIns,
packageAccessHandler = null,
lookupTracker = LookupTracker.DO_NOTHING
)
moduleDescriptor.setDependencies(dependencies + moduleDescriptor)
testServices.moduleDescriptorProvider.replaceModuleDescriptorForModule(module, moduleDescriptor)
return BinaryArtifacts.Js.JsKlibArtifact(File(outputFile), moduleDescriptor, lib)
}
}
@@ -25,9 +25,12 @@ class JsAstHandler(testServices: TestServices) : JsBinaryArtifactHandler(testSer
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val ktFiles = module.files.filter { it.isKtFile }.map { it.originalContent }
val result = (info.unwrap() as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsBoxRunner suppose to work only with old js backend")
processJsProgram((result as TranslationResult.Success).program, ktFiles, module.targetBackend!!) {
val jsProgram = when (val artifact = info.unwrap()) {
is BinaryArtifacts.Js.OldJsArtifact -> (artifact.translationResult as TranslationResult.Success).program
is BinaryArtifacts.Js.JsIrArtifact -> artifact.compilerResult.outputs?.jsProgram ?: return
else -> return
}
processJsProgram(jsProgram, ktFiles, module.targetBackend!!) {
testServices.assertions.fail { it }
}
}
@@ -5,17 +5,28 @@
package org.jetbrains.kotlin.js.testNew.handlers
import org.jetbrains.kotlin.js.test.esModulesSubDir
import org.jetbrains.kotlin.js.test.v8tool
import org.jetbrains.kotlin.js.testNew.utils.*
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.defaultsProvider
import org.jetbrains.kotlin.test.services.moduleStructure
import java.io.File
class JsBoxRunner(testServices: TestServices) : AbstractJsArtifactsCollector(testServices) {
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
if (someAssertionWasFailed) return
if (JsEnvironmentConfigurationDirectives.ES_MODULES in testServices.moduleStructure.allDirectives) {
runEsCode()
} else {
runJsCode()
}
}
private fun runJsCode() {
val globalDirectives = testServices.moduleStructure.allDirectives
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
@@ -45,6 +56,35 @@ class JsBoxRunner(testServices: TestServices) : AbstractJsArtifactsCollector(tes
}
}
private fun runEsCode() {
val globalDirectives = testServices.moduleStructure.allDirectives
val esmOutputDir = JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).esModulesSubDir
val esmDceOutputDir = JsEnvironmentConfigurator.getDceJsArtifactsOutputDir(testServices).esModulesSubDir
val esmPirOutputDir = JsEnvironmentConfigurator.getPirJsArtifactsOutputDir(testServices).esModulesSubDir
val dontSkipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE !in globalDirectives
val dontSkipDceDriven = JsEnvironmentConfigurationDirectives.SKIP_DCE_DRIVEN !in globalDirectives
val runIrDce = JsEnvironmentConfigurationDirectives.RUN_IR_DCE in globalDirectives
val runIrPir = JsEnvironmentConfigurationDirectives.RUN_IR_PIR in globalDirectives
if (dontSkipRegularMode) {
singleRunEsCode(esmOutputDir)
if (runIrDce) {
singleRunEsCode(esmDceOutputDir)
}
}
if (runIrPir && dontSkipDceDriven) {
singleRunEsCode(esmPirOutputDir)
}
}
private fun singleRunEsCode(esmOutputDir: File) {
val perFileEsModuleFile = "$esmOutputDir/test.mjs"
val (allNonEsModuleFiles, inputJsFilesAfter) = extractAllFilesForEsRunner(testServices, modulesToArtifact, esmOutputDir)
v8tool.run(*allNonEsModuleFiles.toTypedArray(), perFileEsModuleFile, *inputJsFilesAfter.toTypedArray())
}
private fun runGeneratedCode(jsFiles: List<String>, testModuleName: String?, testPackage: String?, withModuleSystem: Boolean) {
getTestChecker(testServices)
.check(jsFiles, testModuleName, testPackage, TEST_FUNCTION, DEFAULT_EXPECTED_RESULT, withModuleSystem)
@@ -0,0 +1,104 @@
/*
* Copyright 2010-2021 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.js.testNew.handlers
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.CompilationOutputs
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.toResolverLogger
import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.test.esModulesSubDir
import org.jetbrains.kotlin.js.testNew.converters.ClassicJsBackendFacade.Companion.wrapWithModuleEmulationMarkers
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.backend.handlers.JsBinaryArtifactHandler
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.util.DummyLogger
import java.io.File
class JsIrArtifactsDumpHandler(testServices: TestServices) : JsBinaryArtifactHandler(testServices) {
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
when (val artifact = info.unwrap()) {
is BinaryArtifacts.Js.JsIrArtifact -> {
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val moduleId = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
val moduleKind = configuration.get(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name) + ".js")
val outputDceFile = File(JsEnvironmentConfigurator.getDceJsArtifactPath(testServices, module.name) + ".js")
val outputPirFile = File(JsEnvironmentConfigurator.getPirJsArtifactPath(testServices, module.name) + ".js")
val runIrPir = JsEnvironmentConfigurationDirectives.RUN_IR_PIR in module.directives
val dontSkipDceDriven = JsEnvironmentConfigurationDirectives.SKIP_DCE_DRIVEN !in module.directives
val dontSkipRegularMode = JsEnvironmentConfigurationDirectives.SKIP_REGULAR_MODE !in module.directives
if (dontSkipRegularMode) {
artifact.compilerResult.outputs!!.writeTo(outputFile, moduleId, moduleKind)
artifact.compilerResult.outputsAfterDce?.writeTo(outputDceFile, moduleId, moduleKind)
} else if (runIrPir && dontSkipDceDriven) {
artifact.compilerResult.outputs!!.writeTo(outputPirFile, moduleId, moduleKind)
} else {
TODO("unreachable")
}
}
is BinaryArtifacts.Js.JsKlibArtifact -> {
testServices.jsLibraryProvider.setDescriptorAndLibraryByName(info.outputFile.absolutePath, artifact.descriptor as ModuleDescriptorImpl, artifact.library)
}
is BinaryArtifacts.Js.JsEsArtifact -> {
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val moduleName = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
val esmTestFile = info.outputFile.parentFile.esModulesSubDir.resolve("test.mjs")
createEsTestFile(esmTestFile, moduleName)
val dceEsmTestFile = artifact.outputDceFile?.parentFile?.esModulesSubDir?.resolve("test.mjs") ?: return
createEsTestFile(dceEsmTestFile, moduleName)
}
else -> return
}
// TODO write dts
}
private fun createEsTestFile(file: File, moduleName: String) {
val customTestModule = testServices.moduleStructure.modules
.flatMap { it.files }
.singleOrNull { JsEnvironmentConfigurationDirectives.ENTRY_ES_MODULE in it.directives }
val customTestModuleText = customTestModule?.let { testServices.sourceFileProvider.getContentOfSourceFile(it) }
val defaultTestModule =
"""
import { box } from './${moduleName}/index.js';
let res = box();
if (res !== "OK") {
throw "Wrong result: " + String(res);
}
""".trimIndent()
file.writeText(customTestModuleText ?: defaultTestModule)
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
private fun CompilationOutputs.writeTo(outputFile: File, moduleId: String, moduleKind: ModuleKind) {
val wrappedCode = wrapWithModuleEmulationMarkers(jsCode, moduleId = moduleId, moduleKind = moduleKind)
outputFile.write(wrappedCode)
dependencies.forEach { (moduleId, outputs) ->
val moduleWrappedCode = wrapWithModuleEmulationMarkers(outputs.jsCode, moduleKind, moduleId)
val dependencyPath = outputFile.absolutePath.replace("_v5.js", "-${moduleId}_v5.js")
File(dependencyPath).write(moduleWrappedCode)
}
}
private fun File.write(text: String) {
parentFile.mkdirs()
writeText(text)
}
}
@@ -28,8 +28,9 @@ class JsMinifierRunner(testServices: TestServices) : AbstractJsArtifactsCollecto
val globalDirectives = testServices.moduleStructure.allDirectives
val dontRunGeneratedCode = globalDirectives[JsEnvironmentConfigurationDirectives.DONT_RUN_GENERATED_CODE]
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
if (dontRunGeneratedCode) return
if (dontRunGeneratedCode || esModules) return
val allJsFiles = getOnlyJsFilesForRunner(testServices, modulesToArtifact)
@@ -35,7 +35,7 @@ class JsSourceMapHandler(testServices: TestServices) : JsBinaryArtifactHandler(t
override fun processModule(module: TestModule, info: BinaryArtifacts.Js) {
val outputFile = File(JsEnvironmentConfigurator.getJsModuleArtifactPath(testServices, module.name))
val result = (info.unwrap() as? BinaryArtifacts.Js.OldJsArtifact)?.translationResult
?: throw IllegalArgumentException("JsBoxRunner suppose to work only with old js backend")
?: throw IllegalArgumentException("JsSourceMapHandler suppose to work only with old js backend")
val remap = JsEnvironmentConfigurationDirectives.SKIP_SOURCEMAP_REMAPPING !in module.directives
checkSourceMap(outputFile, (result as TranslationResult.Success).program, remap) { expected, actual ->
testServices.assertions.assertEquals(expected, actual)
@@ -7,13 +7,13 @@ package org.jetbrains.kotlin.js.testNew.handlers
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.js.testNew.utils.extractTestPackage
import org.jetbrains.kotlin.js.testNew.utils.getMainModuleName
import org.jetbrains.kotlin.js.testNew.utils.getOnlyJsFilesForRunner
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator.Companion.getMainModuleName
import org.jetbrains.kotlin.test.services.defaultsProvider
import org.jetbrains.kotlin.test.services.moduleStructure
import java.io.File
@@ -30,8 +30,9 @@ class NodeJsGeneratorHandler(testServices: TestServices) : AbstractJsArtifactsCo
.contains(testServices.defaultsProvider.defaultTargetBackend?.name)
val generateNodeJsRunner = JsEnvironmentConfigurationDirectives.GENERATE_NODE_JS_RUNNER in globalDirectives
val skipNodeJs = JsEnvironmentConfigurationDirectives.SKIP_NODE_JS in globalDirectives
val esModules = JsEnvironmentConfigurationDirectives.ES_MODULES in globalDirectives
if (dontRunGeneratedCode || !generateNodeJsRunner || skipNodeJs) return
if (dontRunGeneratedCode || !generateNodeJsRunner || skipNodeJs || esModules) return
val mainModuleName = getMainModuleName(testServices)
val outputDir = File(JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices).absolutePath)
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.js.testNew.handlers.JsBoxRunner.Companion.TEST_FUNCT
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.INFER_MAIN_MODULE
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.NO_JS_MODULE_SYSTEM
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.RUN_PLAIN_BOX_FUNCTION
import org.jetbrains.kotlin.test.model.BinaryArtifacts
@@ -21,6 +20,7 @@ import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator.Companion.getMainModule
import java.io.File
private const val MODULE_EMULATION_FILE = "${JsEnvironmentConfigurator.TEST_DATA_DIR_PATH}/moduleEmulation.js"
@@ -52,6 +52,19 @@ private fun extractJsFiles(
return before to after
}
private fun extractMjsFiles(esmOutputDir: File, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>): List<String> {
fun copyInputMjsFile(inputMjsFile: TestFile): String {
val targetFile = File(esmOutputDir, inputMjsFile.name)
targetFile.writeText(inputMjsFile.originalContent)
return targetFile.absolutePath
}
return modulesToArtifact
.flatMap { moduleToArtifact -> moduleToArtifact.key.files }
.filter { it.isMjsFile }
.map { copyInputMjsFile(it) }
}
private fun getAdditionalFiles(testServices: TestServices): List<String> {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
@@ -67,6 +80,14 @@ private fun getAdditionalFiles(testServices: TestServices): List<String> {
return additionalFiles
}
private fun getAdditionalMjsFiles(testServices: TestServices): List<String> {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
return originalFile.parentFile.resolve(originalFile.nameWithoutExtension + ".mjs")
.takeIf { it.exists() }
?.let { listOf(it.absolutePath) } ?: emptyList()
}
private fun getAdditionalMainFiles(testServices: TestServices): List<String> {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
val additionalFiles = mutableListOf<String>()
@@ -98,34 +119,62 @@ fun getAllFilesForRunner(
val additionalFiles = getAdditionalFiles(testServices)
val additionalMainFiles = getAdditionalMainFiles(testServices)
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }
val dceJsFiles = artifactsPaths.map { it.replace(outputDir.absolutePath, dceOutputDir.absolutePath) }
val pirJsFiles = artifactsPaths.map { it.replace(outputDir.absolutePath, pirOutputDir.absolutePath) }
val artifactsPaths = modulesToArtifact.values.map { it.outputFile.absolutePath }.filter { !File(it).isDirectory }
val klibDependencies = modulesToArtifact.values
.filterIsInstance<BinaryArtifacts.Js.JsIrArtifact>()
.singleOrNull()?.let { artifact ->
artifact.compilerResult?.outputs?.dependencies?.map { (moduleId, _) ->
artifact.outputFile.absolutePath.replace("_v5.js", "-${moduleId}_v5.js")
}
} ?: emptyList()
val dceJsFiles = (klibDependencies + artifactsPaths).map { it.replace(outputDir.absolutePath, dceOutputDir.absolutePath) }
val pirJsFiles = (klibDependencies + artifactsPaths).map { it.replace(outputDir.absolutePath, pirOutputDir.absolutePath) }
val allJsFiles = additionalFiles + inputJsFilesBefore + artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
val allJsFiles = additionalFiles + inputJsFilesBefore + klibDependencies + artifactsPaths + commonFiles + additionalMainFiles + inputJsFilesAfter
val dceAllJsFiles = additionalFiles + inputJsFilesBefore + dceJsFiles + commonFiles + additionalMainFiles + inputJsFilesAfter
val pirAllJsFiles = additionalFiles + inputJsFilesBefore + pirJsFiles + commonFiles + additionalMainFiles + inputJsFilesAfter
return Triple(allJsFiles, dceAllJsFiles, pirAllJsFiles)
}
fun extractAllFilesForEsRunner(
testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>, esmOutputDir: File
): Pair<List<String>, List<String>> {
val originalFile = testServices.moduleStructure.originalTestDataFiles.first()
val commonFiles = JsAdditionalSourceProvider.getAdditionalJsFiles(originalFile.parent).map { it.absolutePath }
val (inputJsFilesBefore, inputJsFilesAfter) = extractJsFiles(testServices, modulesToArtifact)
val additionalFiles = getAdditionalFiles(testServices)
val additionalMjsFiles = getAdditionalMjsFiles(testServices)
val additionalMainFiles = getAdditionalMainFiles(testServices)
val allNonEsModuleFiles = additionalFiles + inputJsFilesBefore + commonFiles
// Copy __main file if present
if (additionalMainFiles.isNotEmpty()) {
val newFileName = File(esmOutputDir, "test.mjs")
newFileName.delete()
File(additionalMainFiles.first()).copyTo(newFileName)
}
// Copy all .mjs files into generated directory
modulesToArtifact
.flatMap { moduleToArtifact -> moduleToArtifact.key.files }
.filter { it.isMjsFile }
.map { File(esmOutputDir, it.name).writeText(it.originalContent) }
additionalMjsFiles.forEach { mjsFile ->
val outFile = File(esmOutputDir, File(mjsFile).name)
File(mjsFile).copyTo(outFile, overwrite = true)
}
return Pair(allNonEsModuleFiles, inputJsFilesAfter)
}
fun getOnlyJsFilesForRunner(testServices: TestServices, modulesToArtifact: Map<TestModule, BinaryArtifacts.Js>): List<String> {
return getAllFilesForRunner(testServices, modulesToArtifact).first
}
private fun getMainModule(testServices: TestServices): TestModule {
val modules = testServices.moduleStructure.modules
val inferMainModule = INFER_MAIN_MODULE in testServices.moduleStructure.allDirectives
return when {
inferMainModule -> modules.last()
else -> modules.singleOrNull { it.name == ModuleStructureExtractor.DEFAULT_MODULE_NAME } ?: modules.single()
}
}
fun getMainModuleName(testServices: TestServices): String {
return getMainModule(testServices).name
}
fun getTestModuleName(testServices: TestServices): String? {
val runPlainBoxFunction = RUN_PLAIN_BOX_FUNCTION in testServices.moduleStructure.allDirectives
if (runPlainBoxFunction) return null
@@ -144,10 +193,10 @@ fun extractTestPackage(testServices: TestServices): String? {
}
}
return ktFiles.single { ktFile ->
return ktFiles.singleOrNull { ktFile ->
val boxFunction = ktFile.declarations.find { it is KtNamedFunction && it.name == TEST_FUNCTION }
boxFunction != null
}.packageFqName.asString().takeIf { it.isNotEmpty() }
}?.packageFqName?.asString()?.takeIf { it.isNotEmpty() }
}
fun getTestChecker(testServices: TestServices): AbstractJsTestChecker {
@@ -3,123 +3,126 @@
* 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.ir.semantics;
package org.jetbrains.kotlin.js.testNew;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
/** This class is generated by {@link GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/codegen/boxError")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class IrJsCodegenBoxErrorTestGenerated extends AbstractIrJsCodegenBoxErrorTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
@Test
public void testAllFilesPresentInBoxError() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxError"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true, "testsWithJava9", "testsWithJava15", "testsWithJava17", "compileKotlinAgainstKotlin");
}
@Nested
@TestMetadata("compiler/testData/codegen/boxError/semantic")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Semantic extends AbstractIrJsCodegenBoxErrorTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public class Semantic {
@Test
public void testAllFilesPresentInSemantic() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxError/semantic"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("castToErrorType.kt")
public void testCastToErrorType() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/castToErrorType.kt");
}
@Test
@TestMetadata("catchErrorType.kt")
public void testCatchErrorType() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/catchErrorType.kt");
}
@Test
@TestMetadata("evaluationOrder.kt")
public void testEvaluationOrder() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/evaluationOrder.kt");
}
@Test
@TestMetadata("mismatchTypeParameters.kt")
public void testMismatchTypeParameters() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/mismatchTypeParameters.kt");
}
@Test
@TestMetadata("missedBody.kt")
public void testMissedBody() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/missedBody.kt");
}
@Test
@TestMetadata("reifiedNonInline.kt")
public void testReifiedNonInline() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/reifiedNonInline.kt");
}
@Test
@TestMetadata("reifiedWithWrongArguments.kt")
public void testReifiedWithWrongArguments() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/reifiedWithWrongArguments.kt");
}
@Test
@TestMetadata("typeMismatch.kt")
public void testTypeMismatch() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/typeMismatch.kt");
}
@Test
@TestMetadata("unmatchedArguments.kt")
public void testUnmatchedArguments() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/unmatchedArguments.kt");
}
@Test
@TestMetadata("unresolvedFunctionReferece.kt")
public void testUnresolvedFunctionReferece() throws Exception {
runTest("compiler/testData/codegen/boxError/semantic/unresolvedFunctionReferece.kt");
}
}
@Nested
@TestMetadata("compiler/testData/codegen/boxError/syntax")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Syntax extends AbstractIrJsCodegenBoxErrorTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public class Syntax {
@Test
public void testAllFilesPresentInSyntax() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxError/syntax"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("arrowReference.kt")
public void testArrowReference() throws Exception {
runTest("compiler/testData/codegen/boxError/syntax/arrowReference.kt");
}
@Test
@TestMetadata("evaluationOrder.kt")
public void testEvaluationOrder() throws Exception {
runTest("compiler/testData/codegen/boxError/syntax/evaluationOrder.kt");
}
@Test
@TestMetadata("incorectLexicalName.kt")
public void testIncorectLexicalName() throws Exception {
runTest("compiler/testData/codegen/boxError/syntax/incorectLexicalName.kt");
}
@Test
@TestMetadata("missedArgument.kt")
public void testMissedArgument() throws Exception {
runTest("compiler/testData/codegen/boxError/syntax/missedArgument.kt");