Made test runner work with binary compatibility tests
(cherry picked from commit e0b599a632b94e4b1303fc94275dcd5b6a7dfb6b)
This commit is contained in:
committed by
Vasily Levchenko
parent
64445bb793
commit
58ea71cb0e
@@ -220,6 +220,7 @@ def update_external_tests() {
|
||||
include 'compiler/codegen/box/**'
|
||||
include 'compiler/codegen/boxInline/**'
|
||||
include 'compiler/compileKotlinAgainstKotlin/**'
|
||||
include 'compiler/binaryCompatibility/klibEvolution/**'
|
||||
exclude 'stdlib/**'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.process.ExecResult
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
import java.util.function.Function
|
||||
import java.util.function.UnaryOperator
|
||||
@@ -469,6 +470,59 @@ fun runTest() {
|
||||
}
|
||||
}
|
||||
|
||||
class MultiModuleCompilerInvocations {
|
||||
String executablePath
|
||||
Map<String, TestModule> modules
|
||||
List<String> flags
|
||||
|
||||
MultiModuleCompilerInvocations(String executablePath, Map<String, TestModule> modules, List<String> flags) {
|
||||
this.executablePath = executablePath
|
||||
this.modules = modules
|
||||
this.flags = flags
|
||||
}
|
||||
|
||||
def libs = new HashSet<String>()
|
||||
|
||||
String moduleToKlibName(String moduleName, Integer version) {
|
||||
def module = modules[moduleName]
|
||||
// TODO: cleanup
|
||||
def versionSuffix = module.hasVersions ? "_version${version}" : ""
|
||||
return module.hasVersions ? "${executablePath}${versionSuffix}/${moduleName}.klib" : "${executablePath}.${moduleName}.klib"
|
||||
}
|
||||
|
||||
void produceLibrary(TestModule module, Integer moduleVersion, Integer dependencyVersion) {
|
||||
def klibModulePath = moduleToKlibName(module.name, moduleVersion)
|
||||
libs.addAll(module.dependencies)
|
||||
def klibs = module.dependencies.collectMany { ["-l", moduleToKlibName(it, dependencyVersion)] }.toList()
|
||||
def repos = ["-r", "${executablePath}_version${dependencyVersion}", "-r", project.file(executablePath).parentFile.absolutePath ]
|
||||
|
||||
def friends = module.friends ?
|
||||
module.friends.collectMany {
|
||||
["-friend-modules", "${executablePath}.${it}.klib"]
|
||||
}.toList() : []
|
||||
runCompiler(module.versionFiles(moduleVersion).collect { it.path },
|
||||
klibModulePath, flags + ["-p", "library"/*, "-module-name", module.name*/] + repos + klibs + friends)
|
||||
}
|
||||
|
||||
void produceProgram(List<TestFile> compileList, Integer version) {
|
||||
def compileMain = compileList.findAll {
|
||||
it.module.isDefaultModule() || it.module == TestModule.support
|
||||
}
|
||||
compileMain.forEach { f ->
|
||||
libs.addAll(f.module.dependencies)
|
||||
}
|
||||
def friends = compileMain.collectMany { it.module.friends }.toSet()
|
||||
def repos = ["-r", "${executablePath}_version${version}", "-r", project.file(executablePath).parentFile.absolutePath]
|
||||
|
||||
if (!compileMain.empty) {
|
||||
runCompiler(compileMain.collect { it.path }, executablePath, flags + repos +
|
||||
libs.collectMany { ["-l", moduleToKlibName(it, version)] }.toList() +
|
||||
friends.collectMany { ["-friend-modules", "${executablePath}.${it}.klib"] }.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void executeTest() {
|
||||
createOutputDirectory()
|
||||
@@ -519,34 +573,18 @@ fun runTest() {
|
||||
List<TestModule> orderedModules = DFS.INSTANCE.topologicalOrder(modules.values()) { module ->
|
||||
module.dependencies.collect { modules[it] }.findAll { it != null }
|
||||
}
|
||||
Set<String> libs = new HashSet<String>()
|
||||
def compiler = new MultiModuleCompilerInvocations(executablePath(), modules, flags)
|
||||
|
||||
orderedModules.reverse().each { module ->
|
||||
if (!module.isDefaultModule()) {
|
||||
def klibModulePath = "${executablePath()}.${module.name}.klib"
|
||||
libs.addAll(module.dependencies)
|
||||
def klibs = libs.collectMany { ["-l", "${executablePath()}.${it}.klib"] }.toList()
|
||||
def friends = module.friends ?
|
||||
module.friends.collectMany {
|
||||
["-friend-modules", "${executablePath()}.${it}.klib"]
|
||||
}.toList() : []
|
||||
runCompiler(compileList.findAll { it.module == module }.collect { it.path },
|
||||
klibModulePath, flags + ["-p", "library"] + klibs + friends)
|
||||
compiler.produceLibrary(module, 1, 1)
|
||||
if (module.hasVersions) {
|
||||
compiler.produceLibrary(module, 2, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def compileMain = compileList.findAll {
|
||||
it.module.isDefaultModule() || it.module == TestModule.support
|
||||
}
|
||||
compileMain.forEach { f ->
|
||||
libs.addAll(f.module.dependencies)
|
||||
}
|
||||
def friends = compileMain.collectMany {it.module.friends }.toSet()
|
||||
if (!compileMain.empty) {
|
||||
runCompiler(compileMain.collect { it.path }, executablePath(), flags +
|
||||
libs.collectMany { ["-l", "${executablePath()}.${it}.klib"] }.toList() +
|
||||
friends.collectMany {["-friend-modules", "${executablePath()}.${it}.klib"]}.toList()
|
||||
)
|
||||
}
|
||||
compiler.produceProgram(compileList, 2)
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
project.logger.quiet("ERROR: Compilation failed for test suite: $name with exception", ex)
|
||||
|
||||
@@ -5,15 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.TestModule.Companion.default
|
||||
import org.jetbrains.kotlin.TestModule.Companion.support
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
private const val MODULE_DELIMITER = ",\\s*"
|
||||
// This pattern is a copy from the kotlin/compiler/tests-common/tests/org/jetbrains/kotlin/test/TestFiles.java
|
||||
// These patterns are copies from
|
||||
// kotlin/compiler/tests-common/tests/org/jetbrains/kotlin/test/TestFiles.java
|
||||
// kotlin/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java
|
||||
private val FILE_OR_MODULE_PATTERN: Pattern = Pattern.compile("(?://\\s*MODULE:\\s*([^()\\n]+)(?:\\(([^()]+(?:" +
|
||||
"$MODULE_DELIMITER[^()]+)*)\\))?\\s*(?:\\(([^()]+(?:$MODULE_DELIMITER[^()]+)*)\\))?\\s*)?//\\s*FILE:\\s*(.*)$",
|
||||
Pattern.MULTILINE)
|
||||
private val DIRECTIVE_PATTERN = Pattern.compile("^//\\s*[!]?([A-Z_]+)(:[ \\t]*(.*))?$", Pattern.MULTILINE)
|
||||
|
||||
/**
|
||||
* Creates test files from the given source file that may contain different test directives.
|
||||
@@ -82,12 +88,16 @@ private fun String?.parseModuleList() = this
|
||||
* - [support] for a helper sources like Coroutines support.
|
||||
*/
|
||||
data class TestModule(
|
||||
val name: String,
|
||||
val dependencies: List<String>,
|
||||
val friends: List<String>
|
||||
val name: String,
|
||||
val dependencies: List<String>,
|
||||
val friends: List<String>
|
||||
) {
|
||||
val files = mutableListOf<TestFile>()
|
||||
fun isDefaultModule() = this == default || name.endsWith(".main")
|
||||
|
||||
val hasVersions get() = this.files.any { it.version != null }
|
||||
fun versionFiles(version: Int) = this.files.filter { it.version == null || it.version == version }
|
||||
|
||||
companion object {
|
||||
val default = TestModule("default", emptyList(), emptyList())
|
||||
val support = TestModule("support", emptyList(), emptyList())
|
||||
@@ -97,11 +107,33 @@ data class TestModule(
|
||||
/**
|
||||
* Represent a single test file that belongs to the [module].
|
||||
*/
|
||||
data class TestFile(val name: String,
|
||||
val path: String,
|
||||
var text: String = "",
|
||||
val module: TestModule = TestModule.default
|
||||
data class TestFile(
|
||||
val name: String,
|
||||
val path: String,
|
||||
var text: String = "",
|
||||
val module: TestModule = TestModule.default
|
||||
) {
|
||||
init {
|
||||
this.module.files.add(this)
|
||||
}
|
||||
|
||||
val directives: Map<String, String> by lazy {
|
||||
parseDirectives()
|
||||
}
|
||||
|
||||
val version: Int? get() = this.directives["VERSION"]?.toInt()
|
||||
|
||||
fun parseDirectives(): Map<String, String> {
|
||||
val newDirectives = mutableMapOf<String, String>()
|
||||
val directiveMatcher: Matcher = DIRECTIVE_PATTERN.matcher(text)
|
||||
while (directiveMatcher.find()) {
|
||||
val name = directiveMatcher.group(1)
|
||||
val value = directiveMatcher.group(3)
|
||||
newDirectives.put(name, value)
|
||||
}
|
||||
return newDirectives
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes [text] to the file created from the [path].
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user