Introduce special common directives for tests based on foreign annotation tests

This commit is contained in:
Victor Petukhov
2021-04-05 18:08:01 +03:00
parent 6065f0e2d0
commit 1f0616439c
5 changed files with 95 additions and 37 deletions
@@ -18,9 +18,11 @@ abstract class SourceFilePreprocessor(val testServices: TestServices) {
abstract class SourceFileProvider : TestService {
abstract val kotlinSourceDirectory: File
abstract val javaSourceDirectory: File
abstract val javaBinaryDirectory: File
abstract fun getContentOfSourceFile(testFile: TestFile): String
abstract fun getRealFileForSourceFile(testFile: TestFile): File
abstract fun getRealFileForBinaryFile(testFile: TestFile): File
}
val TestServices.sourceFileProvider: SourceFileProvider by TestServices.testServiceAccessor()
@@ -28,6 +30,7 @@ val TestServices.sourceFileProvider: SourceFileProvider by TestServices.testServ
class SourceFileProviderImpl(val testServices: TestServices, val preprocessors: List<SourceFilePreprocessor>) : SourceFileProvider() {
override val kotlinSourceDirectory: File = testServices.createTempDirectory("kotlin-files")
override val javaSourceDirectory: File = testServices.createTempDirectory("java-files")
override val javaBinaryDirectory: File = testServices.createTempDirectory("java-binary-files")
private val contentOfFiles = mutableMapOf<TestFile, String>()
private val realFileMap = mutableMapOf<TestFile, File>()
@@ -52,6 +55,19 @@ class SourceFileProviderImpl(val testServices: TestServices, val preprocessors:
}
}
override fun getRealFileForBinaryFile(testFile: TestFile): File {
return realFileMap.getOrPut(testFile) {
val directory = when {
testFile.isJavaFile -> javaBinaryDirectory
else -> error("Unknown file type: ${testFile.name}")
}
directory.resolve(testFile.relativePath).also {
it.parentFile.mkdirs()
it.writeText(getContentOfSourceFile(testFile))
}
}
}
private fun generateFinalContent(testFile: TestFile): String {
return preprocessors.fold(testFile.originalContent) { content, preprocessor ->
preprocessor.process(testFile, content)
@@ -31,9 +31,22 @@ object JvmEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
val WITH_REFLECT by directive("Add Kotlin reflect to classpath")
val NO_RUNTIME by directive("Don't add any runtime libs to classpath")
val WITH_FOREIGN_ANNOTATIONS by directive("Add foreign nullability annotations to classpath")
val WITH_JSR305_TEST_ANNOTATIONS by directive(
description = """
Add test nullability annotations based on JSR-305 annotations
See directory ./compiler/testData/diagnostics/helpers/jsr305_test_annotations
""".trimIndent()
)
val USE_PSI_CLASS_FILES_READING by directive("Use a slower (PSI-based) class files reading implementation")
val USE_JAVAC by directive("Enable javac integration")
val SKIP_JAVA_SOURCES by directive("Don't add java sources to compile classpath")
val INCLUDE_JAVA_AS_BINARY by directive(
"Compile this java file into jar and add it to classpath instead of compiling Kotlin with Java sources",
applicability = DirectiveApplicability.File
)
val JSPECIFY_MUTE by directive(
"Skip jspecify checks for compliance Kotlin diagnostics to jspecify marks",
@@ -5,21 +5,29 @@
package org.jetbrains.kotlin.test.runners
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.REPORT_JVM_DIAGNOSTICS_ON_FRONTEND
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.SKIP_TXT
import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives.ANNOTATIONS_PATH
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JDK_KIND
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JVM_TARGET
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.STDLIB_JDK8
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.USE_PSI_CLASS_FILES_READING
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_FOREIGN_ANNOTATIONS
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_JSR305_TEST_ANNOTATIONS
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_STDLIB
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler
import org.jetbrains.kotlin.test.frontend.classic.handlers.DeclarationsDumpHandler
import org.jetbrains.kotlin.test.frontend.classic.handlers.OldNewInferenceMetaInfoProcessor
import org.jetbrains.kotlin.test.model.BackendKind
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.preprocessors.JspecifyTestsPreprocessor
import org.jetbrains.kotlin.test.services.configuration.*
import org.jetbrains.kotlin.test.services.jvm.ForeignAnnotationAgainstCompiledJavaTestSuppressor
import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsSourceFilesProvider
@@ -37,6 +45,8 @@ abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest()
defaultDirectives {
+REPORT_JVM_DIAGNOSTICS_ON_FRONTEND
+WITH_FOREIGN_ANNOTATIONS
+WITH_JSR305_TEST_ANNOTATIONS
}
enableMetaInfoHandler()
@@ -14,10 +14,13 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.MockLibraryUtil.compileJavaFilesLibraryToJar
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.ASSERTIONS_MODE
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.CONSTRUCTOR_CALL_NORMALIZATION_MODE
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.INCLUDE_JAVA_AS_BINARY
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JVM_TARGET
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.LAMBDAS
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.SAM_CONVERSIONS
@@ -36,12 +39,17 @@ import org.jetbrains.kotlin.test.model.DependencyDescription
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.FOREIGN_ANNOTATIONS_SOURCES_PATH
import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.FOREIGN_JDK8_ANNOTATIONS_SOURCES_PATH
import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.JSR_305_TEST_ANNOTATIONS_PATH
import org.jetbrains.kotlin.test.services.jvm.CompiledClassesManager
import org.jetbrains.kotlin.test.services.jvm.compiledClassesManager
import org.jetbrains.kotlin.test.util.KtTestUtil
import org.jetbrains.kotlin.test.util.joinToArrayString
import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.File
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.createTempDirectory
class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
companion object {
@@ -129,16 +137,59 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
configuration.addJvmClasspathRoot(ForTestCompileRuntime.runtimeJarForTestsWithJdk8())
}
if (JvmEnvironmentConfigurationDirectives.WITH_FOREIGN_ANNOTATIONS in registeredDirectives) {
val annotationPath = registeredDirectives[ForeignAnnotationsDirectives.ANNOTATIONS_PATH].singleOrNull()
?: JdkForeignAnnotationType.Jdk8Annotations
val javaFilesDir = createTempDirectory().toFile().also {
File(annotationPath.path).copyRecursively(it)
}
val jar = compileJavaFilesLibraryToJar(
javaFilesDir.path,
"foreign-annotations",
assertions = JUnit5Assertions,
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath }
)
configuration.addJvmClasspathRoot(jar)
configuration.addJvmClasspathRoot(ForTestCompileRuntime.jvmAnnotationsForTests())
}
if (JvmEnvironmentConfigurationDirectives.WITH_JSR305_TEST_ANNOTATIONS in registeredDirectives) {
val javaFilesDir = createTempDirectory().toFile().also {
File(JSR_305_TEST_ANNOTATIONS_PATH).copyRecursively(it)
}
val jar = compileJavaFilesLibraryToJar(
javaFilesDir.path,
"jsr-305-test-annotations",
assertions = JUnit5Assertions,
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath }
)
configuration.addJvmClasspathRoot(jar)
}
val isIr = module.targetBackend?.isIR == true
configuration.put(JVMConfigurationKeys.IR, isIr)
if (JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES !in module.directives) {
module.javaFiles.takeIf { it.isNotEmpty() }?.let { javaFiles ->
val javaSourceFiles = module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY !in it.directives }
javaSourceFiles.takeIf { it.isNotEmpty() }?.let { javaFiles ->
javaFiles.forEach { testServices.sourceFileProvider.getRealFileForSourceFile(it) }
configuration.addJavaSourceRoot(testServices.sourceFileProvider.javaSourceDirectory)
}
}
val javaBinaryFiles = module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY in it.directives }
javaBinaryFiles.takeIf { it.isNotEmpty() }?.let { javaFiles ->
javaFiles.forEach { testServices.sourceFileProvider.getRealFileForBinaryFile(it) }
val jar = compileJavaFilesLibraryToJar(
testServices.sourceFileProvider.javaBinaryDirectory.path,
"java-binaries",
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath },
assertions = JUnit5Assertions
)
configuration.addJvmClasspathRoot(jar)
}
configuration.registerModuleDependencies(module)
if (JvmEnvironmentConfigurationDirectives.USE_PSI_CLASS_FILES_READING in module.directives) {
@@ -30,53 +30,21 @@ open class JvmForeignAnnotationsConfigurator(testServices: TestServices) : Envir
companion object {
val FOREIGN_ANNOTATIONS_SOURCES_PATH = Annotations.path
val FOREIGN_JDK8_ANNOTATIONS_SOURCES_PATH = Jdk8Annotations.path
val JSR_305_TEST_ANNOTATIONS_PATH = "compiler/testData/diagnostics/helpers/jsr305_test_annotations"
}
override val directivesContainers: List<DirectivesContainer>
get() = listOf(ForeignAnnotationsDirectives)
@OptIn(ExperimentalStdlibApi::class)
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
val extraClassPath = buildList {
val foreignAnnotations = createJarWithForeignAnnotations(module)
addAll(foreignAnnotations)
addAll(compileTestAnnotations(foreignAnnotations))
}
configuration.addJvmClasspathRoots(extraClassPath)
}
protected fun createJarWithForeignAnnotations(module: TestModule): List<File> {
val directive = ForeignAnnotationsDirectives.ANNOTATIONS_PATH
val annotationsPath = module.directives.singleOrZeroValue(directive)
?.path
?: error("${directive.name} should be specified in test or test runner")
return listOf(
MockLibraryUtil.compileJavaFilesLibraryToJar(annotationsPath, "foreign-annotations", assertions = JUnit5Assertions),
ForTestCompileRuntime.jvmAnnotationsForTests()
)
}
protected fun compileTestAnnotations(extraClassPath: List<File>): List<File> =
listOf(
MockLibraryUtil.compileJavaFilesLibraryToJar(
TEST_ANNOTATIONS_SOURCE_PATH,
"test-foreign-annotations",
extraOptions = listOf("-Xallow-kotlin-package"),
extraClasspath = extraClassPath.map { it.path },
assertions = JUnit5Assertions
)
)
override fun provideAdditionalAnalysisFlags(directives: RegisteredDirectives): Map<AnalysisFlag<*>, Any?> {
val globalState = directives.singleOrZeroValue(JSR305_GLOBAL_REPORT) ?: ReportLevel.STRICT
val globalState = directives.singleOrZeroValue(JSR305_GLOBAL_REPORT) ?: ReportLevel.WARN
val migrationState = directives.singleOrZeroValue(JSR305_MIGRATION_REPORT)
val userAnnotationsState = directives[JSR305_SPECIAL_REPORT].mapNotNull {
val (name, stateDescription) = it.split(":").takeIf { it.size == 2 } ?: return@mapNotNull null
val state = ReportLevel.findByDescription(stateDescription) ?: return@mapNotNull null
name to state
}.toMap()
val jSpecifyReportLevel = directives.singleOrZeroValue(JSPECIFY_STATE) ?: ReportLevel.STRICT
val jSpecifyReportLevel = directives.singleOrZeroValue(JSPECIFY_STATE) ?: ReportLevel.WARN
return mapOf(
JvmAnalysisFlags.javaTypeEnhancementState to JavaTypeEnhancementState(
globalState,