diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index e3404314fce..c5c3552a9f2 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -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 diff --git a/kotlin-native/build-tools/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy b/kotlin-native/build-tools/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy index 9ee3ed16055..efea7d273d4 100644 --- a/kotlin-native/build-tools/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy +++ b/kotlin-native/build-tools/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy @@ -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() // 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 modules = compileList.stream() .map { it.module } .distinct() - .collect(Collectors.toMap({ it.name }, UnaryOperator.identity() )) + .collect(Collectors.toMap({ it.name }, UnaryOperator.identity())) List 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) diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/MultiModule.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/MultiModule.kt index 91a9b2dbda1..46dd1bd7eb8 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/MultiModule.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/MultiModule.kt @@ -61,7 +61,7 @@ class MultiModuleCompilerInvocations( fun produceProgram(compileList: List) { 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) diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/TestDirectives.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/TestDirectives.kt index ab668095e6b..e6b9f150bf7 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/TestDirectives.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/TestDirectives.kt @@ -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 { // 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().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 ) { val files = mutableListOf() - 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 }