diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibABITestCase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibABITestCase.kt deleted file mode 100644 index 4b91c3f9bc8..00000000000 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibABITestCase.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.klib - -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.klib.AbstractKlibABITestCase.Companion.ModuleBuildDirs.Companion.OUTPUT_DIR_NAME -import org.jetbrains.kotlin.klib.AbstractKlibABITestCase.Companion.ModuleBuildDirs.Companion.SOURCE_DIR_NAME -import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase -import org.junit.jupiter.api.fail -import java.io.File -import kotlin.io.path.createTempDirectory - -abstract class AbstractKlibABITestCase : KtUsefulTestCase() { - protected lateinit var buildDir: File - protected lateinit var environment: KotlinCoreEnvironment - - override fun setUp() { - super.setUp() - buildDir = createTempDirectory().toFile().also { it.mkdirs() } - - environment = KotlinCoreEnvironment.createForTests( - testRootDisposable, - CompilerConfiguration(), - EnvironmentConfigFiles.JS_CONFIG_FILES - ) - } - - override fun tearDown() { - buildDir.deleteRecursively() - } - - protected abstract fun stdlibFile(): File - - protected abstract fun buildKlib( - moduleName: String, - moduleSourceDir: File, - moduleDependencies: Collection, - klibFile: File - ) - - protected abstract fun buildBinaryAndRun( - mainModuleKlibFile: File, - libraries: Collection - ) - - fun doTest(testPath: String) = Companion.doTest( - testDir = File(testPath).absoluteFile, - buildDir = buildDir, - stdlibFile = stdlibFile(), - buildKlib = ::buildKlib, - buildBinaryAndRun = ::buildBinaryAndRun, - onNonEmptyBuildDirectory = { directory -> directory.listFiles()?.forEach(File::deleteRecursively) }, - onIgnoredTest = { /* Do nothing specific. JUnit 3 does not support programmatic tests muting. */ } - ) - - companion object { - fun doTest( - testDir: File, - buildDir: File, - stdlibFile: File, - buildKlib: (moduleName: String, moduleSourceDir: File, moduleDependencies: Collection, klibFile: File) -> Unit, - buildBinaryAndRun: (mainModuleKlibFile: File, allDependencies: Collection) -> Unit, - onNonEmptyBuildDirectory: (directory: File) -> Unit, - onIgnoredTest: () -> Unit - ) { - val projectName = testDir.name - - val projectInfoFile = File(testDir, PROJECT_INFO_FILE) - val projectInfo: ProjectInfo = ProjectInfoParser(projectInfoFile).parse(projectName) - - if (projectInfo.muted) { - onIgnoredTest() // Ignore muted tests. - return - } - - val modulesMap: Map = buildMap { - projectInfo.modules.forEach { moduleName -> - val moduleTestDir = File(testDir, moduleName) - assertExists(moduleTestDir) - - val moduleInfoFile = File(moduleTestDir, MODULE_INFO_FILE) - val moduleInfo = ModuleInfoParser(moduleInfoFile).parse(moduleName) - - val moduleBuildDirs = createModuleDirs(buildDir, moduleName) - - // Populate the source dir with *.kt files. - val moduleSourceDir = moduleBuildDirs.sourceDir.apply { mkdirs() } - moduleTestDir.walk().filter { it.isFile && it.extension == "kt" }.forEach { sourceFile -> - val destFile = moduleSourceDir.resolve(sourceFile.relativeTo(moduleTestDir)) - destFile.parentFile.mkdirs() - sourceFile.copyTo(destFile) - } - - val moduleOutputDir = moduleBuildDirs.outputDir.apply { mkdirs() } - val klibFile = moduleOutputDir.resolve("$moduleName.klib") - - this[moduleName] = ModuleUnderTest( - info = moduleInfo, - testDir = moduleTestDir, - buildDirs = moduleBuildDirs, - klibFile = klibFile - ) - } - } - - projectInfo.steps.forEach { projectStep -> - projectStep.order.forEach { moduleName -> - val (moduleInfo, moduleTestDir, moduleBuildDirs, klibFile) = modulesMap[moduleName] - ?: fail { "No module $moduleName found on step ${projectStep.id}" } - - val moduleStep = moduleInfo.steps[projectStep.id] - - moduleStep.modifications.forEach { modification -> - modification.execute(moduleTestDir, moduleBuildDirs.sourceDir) - } - - if (!moduleBuildDirs.outputDir.list().isNullOrEmpty()) - onNonEmptyBuildDirectory(moduleBuildDirs.outputDir) - - val moduleDependencies = moduleStep.dependencies.map { dependencyName -> - if (dependencyName == "stdlib") - stdlibFile - else - modulesMap[dependencyName]?.klibFile ?: fail { "No module $dependencyName found on step ${projectStep.id}" } - } - - buildKlib(moduleInfo.moduleName, moduleBuildDirs.sourceDir, moduleDependencies, klibFile) - } - } - - val mainModuleKlibFile = modulesMap[MAIN_MODULE_NAME]?.klibFile ?: fail { "No main module $MAIN_MODULE_NAME found" } - val allKlibs = buildSet { - this += stdlibFile - modulesMap.mapTo(this) { (_, module) -> module.klibFile } - } - - buildBinaryAndRun(mainModuleKlibFile, allKlibs) - } - - fun createModuleDirs(buildDir: File, moduleName: String): ModuleBuildDirs { - val moduleBuildDir = buildDir.resolve(moduleName) - - val moduleSourceDir = moduleBuildDir.resolve(SOURCE_DIR_NAME).apply { mkdirs() } - val moduleOutputDir = moduleBuildDir.resolve(OUTPUT_DIR_NAME).apply { mkdirs() } - - return ModuleBuildDirs(moduleSourceDir, moduleOutputDir) - } - - data class ModuleBuildDirs(val sourceDir: File, val outputDir: File) { - internal companion object { - const val SOURCE_DIR_NAME = "sources" - const val OUTPUT_DIR_NAME = "outputs" - } - } - - private data class ModuleUnderTest( - val info: ModuleInfo, - val testDir: File, - val buildDirs: ModuleBuildDirs, - val klibFile: File - ) - - const val MAIN_MODULE_NAME = "main" - } -} \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/klib/KlibABITestUtils.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/klib/KlibABITestUtils.kt new file mode 100644 index 00000000000..c7c8adf0729 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/klib/KlibABITestUtils.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2010-2022 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.klib + +import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.klib.KlibABITestUtils.ModuleBuildDirs.Companion.OUTPUT_DIR_NAME +import org.jetbrains.kotlin.klib.KlibABITestUtils.ModuleBuildDirs.Companion.SOURCE_DIR_NAME +import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase +import org.junit.jupiter.api.fail +import java.io.File + +object KlibABITestUtils { + interface TestConfiguration { + val testDir: File + val buildDir: File + val stdlibFile: File + + fun buildKlib(moduleName: String, moduleSourceDir: File, moduleDependencies: Collection, klibFile: File) + fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Collection) + + fun onNonEmptyBuildDirectory(directory: File) + + fun isIgnoredTest(projectInfo: ProjectInfo): Boolean = projectInfo.muted + fun onIgnoredTest() + } + + fun runTest(testConfiguration: TestConfiguration) = with(testConfiguration) { + val projectName = testDir.name + + val projectInfoFile = File(testDir, PROJECT_INFO_FILE) + val projectInfo: ProjectInfo = ProjectInfoParser(projectInfoFile).parse(projectName) + + if (isIgnoredTest(projectInfo)) { + return onIgnoredTest() // Ignore muted tests. + } + + val modulesMap: Map = buildMap { + projectInfo.modules.forEach { moduleName -> + val moduleTestDir = File(testDir, moduleName) + KtUsefulTestCase.assertExists(moduleTestDir) + + val moduleInfoFile = File(moduleTestDir, MODULE_INFO_FILE) + val moduleInfo = ModuleInfoParser(moduleInfoFile).parse(moduleName) + + val moduleBuildDirs = createModuleDirs(buildDir, moduleName) + + // Populate the source dir with *.kt files. + val moduleSourceDir = moduleBuildDirs.sourceDir.apply { mkdirs() } + moduleTestDir.walk().filter { it.isFile && it.extension == "kt" }.forEach { sourceFile -> + val destFile = moduleSourceDir.resolve(sourceFile.relativeTo(moduleTestDir)) + destFile.parentFile.mkdirs() + sourceFile.copyTo(destFile) + } + + val moduleOutputDir = moduleBuildDirs.outputDir.apply { mkdirs() } + val klibFile = moduleOutputDir.resolve("$moduleName.klib") + + this[moduleName] = ModuleUnderTest( + info = moduleInfo, + testDir = moduleTestDir, + buildDirs = moduleBuildDirs, + klibFile = klibFile + ) + } + } + + projectInfo.steps.forEach { projectStep -> + projectStep.order.forEach { moduleName -> + val (moduleInfo, moduleTestDir, moduleBuildDirs, klibFile) = modulesMap[moduleName] + ?: fail { "No module $moduleName found on step ${projectStep.id}" } + + val moduleStep = moduleInfo.steps[projectStep.id] + + moduleStep.modifications.forEach { modification -> + modification.execute(moduleTestDir, moduleBuildDirs.sourceDir) + } + + if (!moduleBuildDirs.outputDir.list().isNullOrEmpty()) + onNonEmptyBuildDirectory(moduleBuildDirs.outputDir) + + val moduleDependencies = moduleStep.dependencies.map { dependencyName -> + if (dependencyName == "stdlib") + stdlibFile + else + modulesMap[dependencyName]?.klibFile ?: fail { "No module $dependencyName found on step ${projectStep.id}" } + } + + buildKlib(moduleInfo.moduleName, moduleBuildDirs.sourceDir, moduleDependencies, klibFile) + } + } + + val mainModuleKlibFile = modulesMap[MAIN_MODULE_NAME]?.klibFile ?: fail { "No main module $MAIN_MODULE_NAME found" } + val allKlibs = buildSet { + this += stdlibFile + modulesMap.mapTo(this) { (_, module) -> module.klibFile } + } + + buildBinaryAndRun(mainModuleKlibFile, allKlibs) + } + + fun createModuleDirs(buildDir: File, moduleName: String): ModuleBuildDirs { + val moduleBuildDir = buildDir.resolve(moduleName) + + val moduleSourceDir = moduleBuildDir.resolve(SOURCE_DIR_NAME).apply { mkdirs() } + val moduleOutputDir = moduleBuildDir.resolve(OUTPUT_DIR_NAME).apply { mkdirs() } + + return ModuleBuildDirs(moduleSourceDir, moduleOutputDir) + } + + data class ModuleBuildDirs(val sourceDir: File, val outputDir: File) { + internal companion object { + const val SOURCE_DIR_NAME = "sources" + const val OUTPUT_DIR_NAME = "outputs" + } + } + + private data class ModuleUnderTest( + val info: ModuleInfo, + val testDir: File, + val buildDirs: ModuleBuildDirs, + val klibFile: File + ) + + const val MAIN_MODULE_NAME = "main" +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt index bd02e06afa1..f0bac444fa0 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/AbstractJsKLibABITestCase.kt @@ -12,6 +12,7 @@ import com.intellij.psi.PsiManager import com.intellij.psi.SingleRootFileViewProvider import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration @@ -25,11 +26,14 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.testOld.V8IrJsTestChecker -import org.jetbrains.kotlin.klib.AbstractKlibABITestCase +import org.jetbrains.kotlin.klib.KlibABITestUtils +import org.jetbrains.kotlin.klib.KlibABITestUtils.MAIN_MODULE_NAME import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.serialization.js.ModuleKind +import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import java.io.File +import kotlin.io.path.createTempDirectory abstract class AbstractJsKLibABIWithICTestCase : AbstractJsKLibABITestCase() { override val useIncrementalCompiler get() = true @@ -39,12 +43,51 @@ abstract class AbstractJsKLibABINoICTestCase : AbstractJsKLibABITestCase() { override val useIncrementalCompiler get() = false } -abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() { +abstract class AbstractJsKLibABITestCase : KtUsefulTestCase() { abstract val useIncrementalCompiler: Boolean - override fun stdlibFile(): File = File("libraries/stdlib/js-ir/build/classes/kotlin/js/main").absoluteFile + private lateinit var buildDir: File + private lateinit var environment: KotlinCoreEnvironment - override fun buildKlib(moduleName: String, moduleSourceDir: File, moduleDependencies: Collection, klibFile: File) { + override fun setUp() { + super.setUp() + buildDir = createTempDirectory().toFile().also { it.mkdirs() } + + environment = KotlinCoreEnvironment.createForTests( + testRootDisposable, + CompilerConfiguration(), + EnvironmentConfigFiles.JS_CONFIG_FILES + ) + } + + override fun tearDown() { + buildDir.deleteRecursively() + } + + private inner class JsTestConfiguration(testPath: String) : KlibABITestUtils.TestConfiguration { + override val testDir: File = File(testPath).absoluteFile + override val buildDir: File get() = this@AbstractJsKLibABITestCase.buildDir + override val stdlibFile: File get() = File("libraries/stdlib/js-ir/build/classes/kotlin/js/main").absoluteFile + + override fun buildKlib(moduleName: String, moduleSourceDir: File, moduleDependencies: Collection, klibFile: File) = + this@AbstractJsKLibABITestCase.buildKlib(moduleName, moduleSourceDir, moduleDependencies, klibFile) + + override fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Collection) = + this@AbstractJsKLibABITestCase.buildBinaryAndRun(mainModuleKlibFile, allDependencies) + + override fun onNonEmptyBuildDirectory(directory: File) { + directory.listFiles()?.forEach(File::deleteRecursively) + } + + override fun onIgnoredTest() { + /* Do nothing specific. JUnit 3 does not support programmatic tests muting. */ + } + } + + // The entry point to generated test classes. + fun doTest(testPath: String) = KlibABITestUtils.runTest(JsTestConfiguration(testPath)) + + private fun buildKlib(moduleName: String, moduleSourceDir: File, moduleDependencies: Collection, klibFile: File) { val ktFiles = environment.createPsiFiles(moduleSourceDir) val config = environment.configuration.copy() @@ -62,7 +105,7 @@ abstract class AbstractJsKLibABITestCase : AbstractKlibABITestCase() { generateKLib(sourceModule, IrFactoryImpl, klibFile.path, nopack = false, jsOutputName = moduleName) } - override fun buildBinaryAndRun(mainModuleKlibFile: File, libraries: Collection) { + private fun buildBinaryAndRun(mainModuleKlibFile: File, libraries: Collection) { val configuration = environment.configuration.copy() configuration.put(JSConfigurationKeys.PARTIAL_LINKAGE, true) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt index d65f3c9902d..9ce30055e59 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeKlibABITest.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.konan.blackboxtest import com.intellij.testFramework.TestDataFile -import org.jetbrains.kotlin.klib.AbstractKlibABITestCase +import org.jetbrains.kotlin.klib.KlibABITestUtils import org.jetbrains.kotlin.konan.blackboxtest.support.* import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.WithTestRunnerExtras import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.* @@ -25,15 +25,24 @@ import java.io.File abstract class AbstractNativeKlibABITest : AbstractNativeSimpleTest() { private val producedKlibs = linkedMapOf>() // IMPORTANT: The order makes sense! - protected fun runTest(@TestDataFile testPath: String): Unit = AbstractKlibABITestCase.doTest( - testDir = getAbsoluteFile(testPath), - buildDir = buildDir, - stdlibFile = stdlibFile, - buildKlib = ::buildKlib, - buildBinaryAndRun = { _, allDependencies -> buildBinaryAndRun(allDependencies) }, - onNonEmptyBuildDirectory = ::backupDirectoryContents, - onIgnoredTest = { throw TestAbortedException() } - ) + private inner class NativeTestConfiguration(testPath: String) : KlibABITestUtils.TestConfiguration { + override val testDir = getAbsoluteFile(testPath) + override val buildDir get() = this@AbstractNativeKlibABITest.buildDir + override val stdlibFile get() = this@AbstractNativeKlibABITest.stdlibFile + + override fun buildKlib(moduleName: String, moduleSourceDir: File, moduleDependencies: Collection, klibFile: File) = + this@AbstractNativeKlibABITest.buildKlib(moduleName, moduleSourceDir, moduleDependencies, klibFile) + + override fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Collection) = + this@AbstractNativeKlibABITest.buildBinaryAndRun(allDependencies) + + override fun onNonEmptyBuildDirectory(directory: File) = backupDirectoryContents(directory) + + override fun onIgnoredTest() = throw TestAbortedException() + } + + // The entry point to generated test classes. + protected fun runTest(@TestDataFile testPath: String) = KlibABITestUtils.runTest(NativeTestConfiguration(testPath)) private fun buildKlib(moduleName: String, moduleSourceDir: File, moduleDependencies: Collection, klibFile: File) { val module = createModule(moduleName) @@ -66,7 +75,7 @@ abstract class AbstractNativeKlibABITest : AbstractNativeSimpleTest() { } else emptyList() - val (sourceDir, outputDir) = AbstractKlibABITestCase.createModuleDirs(buildDir, LAUNCHER_MODULE_NAME) + val (sourceDir, outputDir) = KlibABITestUtils.createModuleDirs(buildDir, LAUNCHER_MODULE_NAME) val executableFile = outputDir.resolve("app." + testRunSettings.get().testTarget.family.exeSuffix) val module = createModule(LAUNCHER_MODULE_NAME)