From 1b131332ab69d50d6bfd3896b189327bd49e9d3c Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Thu, 9 Jun 2022 15:25:45 +0300 Subject: [PATCH] [Native][tests] Simplify handling opt-ins in the test launcher For a box test, the test engine generates a test launcher -- a function that calls `box` function. The latter might require an opt-in. To deal with this, the test engine was using some heuristics to detect possibly used opt-ins and applied them to the test launcher. This commit provides an alternative solution -- it uses `@Suppress("OPT_IN_USAGE_ERROR")` annotation for the test launcher. This way, it doesn't have to guess which opt-ins to apply. --- .../support/group/ExtTestCaseGroupProvider.kt | 62 +++---------------- .../konan/blackboxtest/support/util/Files.kt | 2 +- 2 files changed, 8 insertions(+), 56 deletions(-) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt index ad969094857..2e118778364 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt @@ -155,9 +155,9 @@ private class ExtTestDataFile( val isStandaloneTest = definitelyStandaloneTest || determineIfStandaloneTest() makeObjectsMutable() patchPackageNames(isStandaloneTest) - val fileLevelAnnotations = patchFileLevelAnnotations() + patchFileLevelAnnotations() val entryPointFunctionFQN = findEntryPoint() - generateTestLauncher(isStandaloneTest, entryPointFunctionFQN, fileLevelAnnotations) + generateTestLauncher(isStandaloneTest, entryPointFunctionFQN) return doCreateTestCase(isStandaloneTest, sharedModules) } @@ -405,54 +405,13 @@ private class ExtTestDataFile( } /** - * 1. Collect all file-level annotations that should be added to the launcher. See [generateTestLauncher]. - * 2. Make sure that the OptIns specified in test directives (see [ExtTestDataFileSettings.optInsForSourceCode]) are represented - * as file-level annotations in every individual test file. + * Make sure that the OptIns specified in test directives (see [ExtTestDataFileSettings.optInsForSourceCode]) are represented + * as file-level annotations in every individual test file. */ - private fun patchFileLevelAnnotations(): List = with(structure) { - val allFileLevelAnnotations = hashSetOf() - + private fun patchFileLevelAnnotations() = with(structure) { fun getAnnotationText(fullyQualifiedName: String) = "@file:${OPT_IN_ANNOTATION_NAME.asString()}($fullyQualifiedName::class)" - // Every OptIn specified in test directive should be represented as a file-level annotation. - testDataFileSettings.optInsForSourceCode.mapTo(allFileLevelAnnotations, ::getAnnotationText) - - // Now, collect file-level annotations already present in test files. - filesToTransform.forEach { handler -> - handler.accept(object : KtTreeVisitorVoid() { - override fun visitKtFile(file: KtFile) { - val importDirectives: Map by lazy { - file.importDirectives.mapNotNull { importDirective -> - val importedFqName = importDirective.importedFqName ?: return@mapNotNull null - val name = importDirective.alias?.name ?: importedFqName.shortName().asString() - name to importedFqName.asString() - }.toMap() - } - - file.annotationEntries.mapNotNullTo(allFileLevelAnnotations) { annotationEntry -> - val constructorCallee = annotationEntry.getChildOfType() - val constructorType = constructorCallee?.typeReference?.getChildOfType() - val constructorTypeName = constructorType?.collectNames()?.singleOrNull() - - if (constructorTypeName != OPT_IN_ANNOTATION_NAME) return@mapNotNullTo null - - val valueArgument = annotationEntry.valueArguments.singleOrNull() - val classLiteral = valueArgument?.getArgumentExpression() as? KtClassLiteralExpression - - if (classLiteral?.getChildOfType() != null) - annotationEntry.text - else - classLiteral?.getChildOfType()?.getReferencedName() - ?.let(importDirectives::get) - ?.let { fullyQualifiedName -> getAnnotationText(fullyQualifiedName) } - } - } - }) - } - - val allFileLevelAnnotationsSorted = allFileLevelAnnotations.sorted() - - // Finally, make sure that every test file contains all the necessary file-level annotations. + // Make sure that every test file contains all the necessary file-level annotations. if (testDataFileSettings.optInsForSourceCode.isNotEmpty()) { filesToTransform.forEach { handler -> handler.accept(object : KtTreeVisitorVoid() { @@ -468,8 +427,6 @@ private class ExtTestDataFile( }) } } - - return allFileLevelAnnotationsSorted } private fun KtFile.addAnnotations(fileAnnotationList: KtFileAnnotationList) { @@ -514,13 +471,8 @@ private class ExtTestDataFile( } /** Adds a wrapper to run it as Kotlin test. */ - private fun generateTestLauncher(isStandaloneTest: Boolean, entryPointFunctionFQN: String, fileLevelAnnotations: List) { + private fun generateTestLauncher(isStandaloneTest: Boolean, entryPointFunctionFQN: String) { val fileText = buildString { - if (fileLevelAnnotations.isNotEmpty()) { - fileLevelAnnotations.forEach(this::appendLine) - appendLine() - } - if (!isStandaloneTest) { append("package ").appendLine(testDataFileSettings.nominalPackageName) appendLine() diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Files.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Files.kt index de271609f93..e20bdd6c52e 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Files.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Files.kt @@ -36,7 +36,7 @@ internal fun generateBoxFunctionLauncher(entryPointFunctionFQN: String): String """ @kotlin.test.Test fun runTest() { - val result = $entryPointFunctionFQN() + val result = @Suppress("OPT_IN_USAGE_ERROR") $entryPointFunctionFQN() kotlin.test.assertEquals("OK", result, "Test failed with: ${'$'}result") }