Fixes to Kotlin/Native test directives infrastructure.
* parse files and modules separately * fix default and support modules usage * add another way to ignore backend (new directive) * add new test to exclude list
This commit is contained in:
@@ -326,8 +326,7 @@ task run_external () {
|
||||
|
||||
rootProject.files(
|
||||
'compiler/testData/codegen/box',
|
||||
'compiler/codegen/boxInline',
|
||||
'compiler/compileKotlinAgainstKotlin'
|
||||
'compiler/testData/codegen/boxInline'
|
||||
).asFileTree.visit { file ->
|
||||
if (!file.isDirectory() || !file.file.list().any{ it.endsWith(".kt")})
|
||||
return
|
||||
|
||||
@@ -86,7 +86,7 @@ class RunExternalTestGroup extends JavaExec implements CompilerRunner {
|
||||
jvmArgs "-Xmx4G"
|
||||
jvmArgs "-Dkonan.home=${UtilsKt.getKotlinNativeDist(project)}"
|
||||
enableAssertions = true
|
||||
def sources = File.createTempFile(name,".lst")
|
||||
def sources = File.createTempFile(name, ".lst")
|
||||
sources.deleteOnExit()
|
||||
def sourcesWriter = sources.newWriter()
|
||||
filesToCompile.each { f ->
|
||||
@@ -281,7 +281,7 @@ class RunExternalTestGroup extends JavaExec implements CompilerRunner {
|
||||
def vars = new HashSet<String>() // variables that has the same name as a package
|
||||
TestModule mainModule = null
|
||||
def testFiles = TestDirectivesKt.buildCompileList(project.rootProject.file(src).toPath(), "$outputDirectory/${project.rootProject.file(src).name}")
|
||||
for (TestFile testFile: testFiles) {
|
||||
for (TestFile testFile : testFiles) {
|
||||
def text = testFile.text
|
||||
def filePath = testFile.path
|
||||
if (text.contains('COROUTINES_PACKAGE')) {
|
||||
@@ -290,9 +290,11 @@ class RunExternalTestGroup extends JavaExec implements CompilerRunner {
|
||||
def pkg
|
||||
if (text =~ packagePattern) {
|
||||
pkg = (text =~ packagePattern)[0][1]
|
||||
packages.add(pkg)
|
||||
pkg = "$sourceName.$pkg"
|
||||
text = text.replaceFirst(packagePattern, "package $pkg")
|
||||
if (!pkg.startsWith("kotlin")) {
|
||||
packages.add(pkg)
|
||||
pkg = "$sourceName.$pkg"
|
||||
text = text.replaceFirst(packagePattern, "package $pkg")
|
||||
}
|
||||
} else {
|
||||
pkg = sourceName
|
||||
text = insertInTextAfter(text, "\npackage $pkg\n", "@file:")
|
||||
@@ -308,7 +310,7 @@ class RunExternalTestGroup extends JavaExec implements CompilerRunner {
|
||||
}
|
||||
testFile.text = text
|
||||
}
|
||||
for (TestFile testFile: testFiles) {
|
||||
for (TestFile testFile : testFiles) {
|
||||
def text = testFile.text
|
||||
// Find if there are any imports in the file
|
||||
def matcher = (text =~ ~/${importRegex}(${fullQualified}*)/)
|
||||
@@ -373,14 +375,21 @@ class RunExternalTestGroup extends JavaExec implements CompilerRunner {
|
||||
testFile.text = res
|
||||
}
|
||||
def launcherText = createLauncherFileText(src, imports)
|
||||
testFiles.add(new TestFile("_launcher.kt", "$outputDirectory/${project.rootProject.file(src).name}/_launcher.kt".toString(),
|
||||
launcherText, mainModule != null ? mainModule : TestModule.default))
|
||||
testFiles.add(
|
||||
new TestFile(
|
||||
"_launcher.kt",
|
||||
"$outputDirectory/$src/_launcher.kt".toString(),
|
||||
launcherText,
|
||||
mainModule ?: testFiles.collect { it.module }.find { it.isDefaultModule() }
|
||||
?: TestModule.default()
|
||||
)
|
||||
)
|
||||
return testFiles
|
||||
}
|
||||
|
||||
String normalize(String name) {
|
||||
return name.replace('.kt', '')
|
||||
.replace('-','_')
|
||||
.replace('-', '_')
|
||||
.replace('.', '_')
|
||||
}
|
||||
|
||||
@@ -420,13 +429,14 @@ fun runTest() {
|
||||
|
||||
static def excludeList = [
|
||||
"compiler/testData/codegen/boxInline/multiplatform/defaultArguments/receiversAndParametersInLambda.kt", // KT-36880
|
||||
"compiler/testData/compileKotlinAgainstKotlin/specialBridgesInDependencies.kt", // KT-42723
|
||||
"compiler/testData/codegen/box/compileKotlinAgainstKotlin/specialBridgesInDependencies.kt", // KT-42723
|
||||
"compiler/testData/codegen/box/collections/kt41123.kt", // KT-42723
|
||||
"compiler/testData/codegen/box/multiplatform/multiModule/expectActualTypealiasLink.kt", // KT-40137
|
||||
"compiler/testData/codegen/box/multiplatform/multiModule/expectActualMemberLink.kt", // KT-33091
|
||||
"compiler/testData/codegen/box/multiplatform/multiModule/expectActualLink.kt", // KT-41901
|
||||
"compiler/testData/codegen/box/coroutines/multiModule/", // KT-40121
|
||||
"compiler/testData/codegen/box/defaultArguments/recursiveDefaultArguments.kt" // KT-42684
|
||||
"compiler/testData/codegen/box/defaultArguments/recursiveDefaultArguments.kt", // KT-42684
|
||||
"compiler/testData/codegen/box/inlineClasses/nestedInlineClass.kt" // KT-45139
|
||||
]
|
||||
|
||||
boolean isEnabledForNativeBackend(String fileName) {
|
||||
@@ -469,7 +479,8 @@ fun runTest() {
|
||||
return false
|
||||
} else {
|
||||
// No target backend. Check if NATIVE backend is ignored.
|
||||
def ignoredBackends = findLinesWithPrefixesRemoved(text, "// IGNORE_BACKEND: ")
|
||||
def ignoredBackends = findLinesWithPrefixesRemoved(text, "// IGNORE_BACKEND: ") +
|
||||
findLinesWithPrefixesRemoved(text, "// DONT_TARGET_EXACT_BACKEND: ")
|
||||
for (String s : ignoredBackends) {
|
||||
if (s.contains("NATIVE")) { return false }
|
||||
}
|
||||
@@ -524,7 +535,7 @@ fun runTest() {
|
||||
Map<String, TestModule> modules = compileList.stream()
|
||||
.map { it.module }
|
||||
.distinct()
|
||||
.collect(Collectors.toMap({ it.name }, UnaryOperator.identity() ))
|
||||
.collect(Collectors.toMap({ it.name }, UnaryOperator.identity()))
|
||||
|
||||
List<TestModule> orderedModules = DFS.INSTANCE.topologicalOrder(modules.values()) { module ->
|
||||
module.dependencies.collect { modules[it] }.findAll { it != null }
|
||||
@@ -561,8 +572,8 @@ fun runTest() {
|
||||
}
|
||||
if (isEnabledForNativeBackend(src)) {
|
||||
suite.executeTest(file.name) {
|
||||
project.logger.quiet(src)
|
||||
runExecutable()
|
||||
project.logger.quiet(src)
|
||||
runExecutable()
|
||||
}
|
||||
} else {
|
||||
suite.skipTest(file.name)
|
||||
|
||||
@@ -61,7 +61,7 @@ class MultiModuleCompilerInvocations(
|
||||
|
||||
fun produceProgram(compileList: List<TestFile>) {
|
||||
val compileMain = compileList.filter {
|
||||
it.module.isDefaultModule() || it.module === TestModule.support
|
||||
it.module.isDefaultModule() || it.module.isSupportModule()
|
||||
}
|
||||
compileMain.forEach { f ->
|
||||
libs.addAll(f.module.dependencies)
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
|
||||
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
|
||||
import java.io.File
|
||||
|
||||
private const val MODULE_DELIMITER = ",\\s*"
|
||||
// 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 MODULE_PATTERN: Pattern = Pattern.compile("//\\s*MODULE:\\s*([^()\\n]+)(?:\\(([^()]+(?:" +
|
||||
MODULE_DELIMITER + "[^()]+)*)\\))?\\s*(?:\\(([^()]+(?:" + MODULE_DELIMITER + "[^()]+)*)\\))?\n")
|
||||
private val FILE_PATTERN = Pattern.compile("//\\s*FILE:\\s*(.*)\n")
|
||||
|
||||
private val DIRECTIVE_PATTERN = Pattern.compile("^//\\s*[!]?([A-Z_]+)(:[ \\t]*(.*))?$", Pattern.MULTILINE)
|
||||
|
||||
/**
|
||||
@@ -32,42 +32,66 @@ fun buildCompileList(source: Path, outputDirectory: String): List<TestFile> {
|
||||
// Remove diagnostic parameters in external tests.
|
||||
val srcText = srcFile.readText().replace(Regex("<!.*?!>(.*?)<!>")) { match -> match.groupValues[1] }
|
||||
|
||||
var supportModule: TestModule? = null
|
||||
if (srcText.contains("// WITH_COROUTINES")) {
|
||||
result.add(TestFile("helpers.kt", "$outputDirectory/helpers.kt", createTextForHelpers(), TestModule.support))
|
||||
supportModule = TestModule.support()
|
||||
result.add(TestFile("helpers.kt", "$outputDirectory/helpers.kt",
|
||||
createTextForHelpers(), supportModule))
|
||||
}
|
||||
|
||||
val matcher = FILE_OR_MODULE_PATTERN.matcher(srcText)
|
||||
if (!matcher.find()) {
|
||||
val defaultModule = TestModule.default()
|
||||
val moduleMatcher = MODULE_PATTERN.matcher(srcText)
|
||||
val fileMatcher = FILE_PATTERN.matcher(srcText)
|
||||
var nextModuleExists = moduleMatcher.find()
|
||||
var nextFileExists = fileMatcher.find()
|
||||
|
||||
if (!nextModuleExists && !nextFileExists) {
|
||||
// There is only one file in the input
|
||||
result.add(TestFile(srcFile.name, "$outputDirectory/${srcFile.name}", srcText))
|
||||
result.add(TestFile(srcFile.name, "$outputDirectory/${srcFile.name}", srcText, defaultModule))
|
||||
} else {
|
||||
// There are several files
|
||||
var processedChars = 0
|
||||
var module: TestModule = TestModule.default
|
||||
var nextFileExists = true
|
||||
while (nextFileExists) {
|
||||
var moduleName = matcher.group(1)
|
||||
val moduleDependencies = matcher.group(2)
|
||||
val moduleFriends = matcher.group(3)
|
||||
var module: TestModule = defaultModule
|
||||
|
||||
if (moduleName != null) {
|
||||
moduleName = moduleName.trim { it <= ' ' }
|
||||
module = TestModule("${srcFile.name}.$moduleName",
|
||||
moduleDependencies.parseModuleList().map {
|
||||
if (it != "support") "${srcFile.name}.$it" else it
|
||||
},
|
||||
while (nextModuleExists || nextFileExists) {
|
||||
if (nextModuleExists) {
|
||||
var moduleName = moduleMatcher.group(1)
|
||||
val moduleDependencies = moduleMatcher.group(2)
|
||||
val moduleFriends = moduleMatcher.group(3)
|
||||
|
||||
if (moduleName != null) {
|
||||
moduleName = moduleName.trim { it <= ' ' }
|
||||
val dependencies = mutableListOf<String>().apply {
|
||||
addAll(moduleDependencies.parseModuleList())
|
||||
if (supportModule != null && !contains("support")) {
|
||||
add("support")
|
||||
}
|
||||
}.map {
|
||||
if (it != "support") "${srcFile.name}.$it" else it
|
||||
}
|
||||
module = TestModule("${srcFile.name}.$moduleName",
|
||||
dependencies,
|
||||
moduleFriends.parseModuleList().map { "${srcFile.name}.$it" })
|
||||
}
|
||||
}
|
||||
|
||||
val fileName = matcher.group(4)
|
||||
val filePath = "$outputDirectory/$fileName"
|
||||
val start = processedChars
|
||||
nextFileExists = matcher.find()
|
||||
val end = if (nextFileExists) matcher.start() else srcText.length
|
||||
val fileText = srcText.substring(start, end)
|
||||
processedChars = end
|
||||
if (fileName.endsWith(".kt")) {
|
||||
result.add(TestFile(fileName, filePath, fileText, module))
|
||||
nextModuleExists = moduleMatcher.find()
|
||||
while (nextFileExists) {
|
||||
val fileName = fileMatcher.group(1)
|
||||
val filePath = "$outputDirectory/$fileName"
|
||||
val start = processedChars
|
||||
nextFileExists = fileMatcher.find()
|
||||
val end = when {
|
||||
nextFileExists && nextModuleExists -> Math.min(fileMatcher.start(), moduleMatcher.start())
|
||||
nextFileExists -> fileMatcher.start()
|
||||
else -> srcText.length
|
||||
}
|
||||
val fileText = srcText.substring(start, end)
|
||||
processedChars = end
|
||||
if (fileName.endsWith(".kt")) {
|
||||
result.add(TestFile(fileName, filePath, fileText, module))
|
||||
}
|
||||
if (nextModuleExists && nextFileExists && fileMatcher.start() > moduleMatcher.start()) break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +103,7 @@ private fun String?.parseModuleList() = this
|
||||
?: emptyList()
|
||||
|
||||
/**
|
||||
* Test module from the test source declared by the [FILE_OR_MODULE_PATTERN].
|
||||
* Test module from the test source declared by the [MODULE_PATTERN].
|
||||
* Module should have a [name] and could have [dependencies] on other modules and [friends].
|
||||
*
|
||||
* There are 2 predefined modules:
|
||||
@@ -92,14 +116,15 @@ data class TestModule(
|
||||
val friends: List<String>
|
||||
) {
|
||||
val files = mutableListOf<TestFile>()
|
||||
fun isDefaultModule() = this == default || name.endsWith(".main")
|
||||
fun isDefaultModule() = this.name == "default" || name.endsWith(".main")
|
||||
fun isSupportModule() = this.name == "support"
|
||||
|
||||
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())
|
||||
@JvmStatic fun default() = TestModule("default", emptyList(), emptyList())
|
||||
@JvmStatic fun support() = TestModule("support", emptyList(), emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +135,7 @@ data class TestFile(
|
||||
val name: String,
|
||||
val path: String,
|
||||
var text: String = "",
|
||||
val module: TestModule = TestModule.default
|
||||
val module: TestModule
|
||||
) {
|
||||
init {
|
||||
this.module.files.add(this)
|
||||
@@ -127,8 +152,8 @@ data class TestFile(
|
||||
val directiveMatcher: Matcher = DIRECTIVE_PATTERN.matcher(text)
|
||||
while (directiveMatcher.find()) {
|
||||
val name = directiveMatcher.group(1)
|
||||
val value = directiveMatcher.group(3)
|
||||
newDirectives.put(name, value)
|
||||
val value = directiveMatcher.group(3) ?: ""
|
||||
newDirectives[name] = value
|
||||
}
|
||||
return newDirectives
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user