[IR][tests] Refactoring: Get rid of AbstractKlibABITestCase

This commit is contained in:
Dmitriy Dolovov
2022-10-17 12:38:13 +02:00
committed by Space Team
parent b5655dfaac
commit f048e3ddf7
4 changed files with 196 additions and 187 deletions
@@ -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<File>,
klibFile: File
)
protected abstract fun buildBinaryAndRun(
mainModuleKlibFile: File,
libraries: Collection<File>
)
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<File>, klibFile: File) -> Unit,
buildBinaryAndRun: (mainModuleKlibFile: File, allDependencies: Collection<File>) -> 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<String, ModuleUnderTest> = 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"
}
}
@@ -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<File>, klibFile: File)
fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Collection<File>)
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<String, ModuleUnderTest> = 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"
}
@@ -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<File>, 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<File>, klibFile: File) =
this@AbstractJsKLibABITestCase.buildKlib(moduleName, moduleSourceDir, moduleDependencies, klibFile)
override fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Collection<File>) =
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<File>, 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<File>) {
private fun buildBinaryAndRun(mainModuleKlibFile: File, libraries: Collection<File>) {
val configuration = environment.configuration.copy()
configuration.put(JSConfigurationKeys.PARTIAL_LINKAGE, true)
@@ -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<KLIB, Collection<File>>() // 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<File>, klibFile: File) =
this@AbstractNativeKlibABITest.buildKlib(moduleName, moduleSourceDir, moduleDependencies, klibFile)
override fun buildBinaryAndRun(mainModuleKlibFile: File, allDependencies: Collection<File>) =
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<File>, 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<KotlinNativeTargets>().testTarget.family.exeSuffix)
val module = createModule(LAUNCHER_MODULE_NAME)