[analysis api, test] rework test infrastructure, add possibility to create multimodule tests

This commit is contained in:
Ilya Kirillov
2022-03-24 22:34:31 +01:00
parent 6831bde751
commit e69fa1ae07
14 changed files with 171 additions and 34 deletions
@@ -0,0 +1,108 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.fir.test.configurators.library
import com.intellij.openapi.Disposable
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.source.AnalysisApiFirSourceTestConfigurator
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiBaseTestServiceRegistrar
import org.jetbrains.kotlin.analysis.api.impl.base.test.configurators.AnalysisApiLibraryBaseTestServiceRegistrar
import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AnalysisApiFirTestServiceRegistrar
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.test.framework.project.structure.TestKtLibrarySourceModule
import org.jetbrains.kotlin.analysis.test.framework.services.libraries.CompiledLibraryProvider
import org.jetbrains.kotlin.analysis.test.framework.services.libraries.compiledLibraryProvider
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestServiceRegistrar
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.ServiceRegistrationData
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
import java.nio.file.Path
object AnalysisApiLibrarySourceTestConfigurator : AnalysisApiTestConfigurator() {
override val analyseInDependentSession: Boolean get() = false
override fun configureTest(
builder: TestConfigurationBuilder,
disposable: Disposable
) {
builder.useAdditionalServices(ServiceRegistrationData(CompiledLibraryProvider::class, ::CompiledLibraryProvider))
}
override fun createModules(
moduleStructure: TestModuleStructure,
testServices: TestServices,
project: Project
): List<KtModuleWithFiles> {
val testModule = moduleStructure.modules.single()
val (libraryJar, librarySourcesJar) = testServices.compiledLibraryProvider.compileToLibrary(testModule)
val libraryKtModule = KtTestLibraryModule(project, testModule, libraryJar)
val librarySourceFiles = LibraryUtils
.getAllPsiFilesFromTheJar(librarySourcesJar, project)
val sourcesKtModule = TestKtLibrarySourceModule(
project,
testModule,
librarySourceFiles,
testServices,
libraryKtModule
)
libraryKtModule.librarySources = sourcesKtModule
return listOf(
KtModuleWithFiles(sourcesKtModule, librarySourceFiles),
)
}
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar> =
listOf(
AnalysisApiBaseTestServiceRegistrar,
AnalysisApiFirTestServiceRegistrar,
AnalysisApiLibraryBaseTestServiceRegistrar,
)
override fun doOutOfBlockModification(file: KtFile) {
AnalysisApiFirSourceTestConfigurator(analyseInDependentSession = false).doOutOfBlockModification(file)
}
}
private class KtTestLibraryModule(
override val project: Project,
private val testModule: TestModule,
private val jar: Path
) : KtLibraryModule {
override val directRegularDependencies: List<KtModule> get() = emptyList()
override val directRefinementDependencies: List<KtModule> get() = emptyList()
override val directFriendDependencies: List<KtModule> get() = emptyList()
override val contentScope: GlobalSearchScope by lazy {
GlobalSearchScope.filesScope(project, LibraryUtils.getAllVirtualFilesFromJar(jar))
}
override fun getBinaryRoots(): Collection<Path> = listOf(jar)
override val libraryName: String get() = testModule.name
override lateinit var librarySources: KtLibrarySourceModule
override val platform: TargetPlatform get() = testModule.targetPlatform
override val analyzerServices: PlatformDependentAnalyzerServices get() = testModule.targetPlatform.getAnalyzerServices()
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.standalone
import com.intellij.openapi.Disposable
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.source.AnalysisApiFirSourceTestConfigurator
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestServiceRegistrar
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
object StandaloneModeConfigurator : AnalysisApiTestConfigurator() {
override val analyseInDependentSession: Boolean get() = false
override fun configureTest(builder: TestConfigurationBuilder, disposable: Disposable) {
AnalysisApiFirSourceTestConfigurator(analyseInDependentSession = false).configureTest(builder, disposable)
}
override val serviceRegistrars: List<AnalysisApiTestServiceRegistrar>
get() = AnalysisApiFirSourceTestConfigurator(analyseInDependentSession = false).serviceRegistrars
override fun createModules(
moduleStructure: TestModuleStructure,
testServices: TestServices,
project: Project
): List<KtModuleWithFiles> {
return AnalysisApiFirSourceTestConfigurator(analyseInDependentSession = false).createModules(moduleStructure, testServices, project)
}
override fun doOutOfBlockModification(file: KtFile) {
AnalysisApiFirSourceTestConfigurator(analyseInDependentSession = false).doOutOfBlockModification(file)
}
}
@@ -10,12 +10,16 @@ import com.intellij.openapi.util.Disposer
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.testFramework.TestDataFile
import junit.framework.ComparisonFailure
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.analyseInDependedAnalysisSession
import org.jetbrains.kotlin.analysis.api.*
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
import org.jetbrains.kotlin.analysis.test.framework.TestWithDisposable
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
import org.jetbrains.kotlin.analysis.test.framework.services.ExpressionMarkerProvider
import org.jetbrains.kotlin.analysis.test.framework.services.ExpressionMarkersSourceFilePreprocessor
import org.jetbrains.kotlin.analysis.test.framework.services.libraries.LibraryWasNotCompiledDueToExpectedCompilationError
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
import org.jetbrains.kotlin.analysis.test.framework.utils.SkipTestException
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
@@ -114,12 +118,6 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() {
useAdditionalService { ExpressionMarkerProvider() }
registerAnalysisApiBaseTestServices(disposable, configurator)
useAdditionalService(::TestKtModuleProvider)
useAdditionalService<ApplicationDisposableProvider> { ExecutionListenerBasedDisposableProvider() }
useAdditionalService<KotlinStandardLibrariesPathProvider> { StandardLibrariesPathProviderForKotlinProject }
useDirectives(AnalysisApiTestDirectives)
configureTest(this)
startingArtifactFactory = { ResultingArtifact.Source() }
@@ -6,13 +6,18 @@
package org.jetbrains.kotlin.analysis.test.framework.base
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
import org.jetbrains.kotlin.analysis.test.framework.project.structure.AnalysisApiKtModuleProvider
import org.jetbrains.kotlin.analysis.test.framework.project.structure.AnalysisApiKtModuleProviderImpl
import org.jetbrains.kotlin.analysis.test.framework.services.*
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator
import org.jetbrains.kotlin.test.ExecutionListenerBasedDisposableProvider
import org.jetbrains.kotlin.test.TestInfrastructureInternals
import org.jetbrains.kotlin.test.bind
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.services.ApplicationDisposableProvider
import org.jetbrains.kotlin.test.services.KotlinStandardLibrariesPathProvider
import org.jetbrains.kotlin.test.services.StandardLibrariesPathProviderForKotlinProject
@OptIn(TestInfrastructureInternals::class)
fun TestConfigurationBuilder.registerAnalysisApiBaseTestServices(
@@ -22,7 +27,10 @@ fun TestConfigurationBuilder.registerAnalysisApiBaseTestServices(
useAdditionalService<TestDisposableProvider>(::TestDisposableProviderImpl)
useAdditionalService<AnalysisApiKtModuleProvider>(::AnalysisApiKtModuleProviderImpl)
useAdditionalService<AnalysisApiEnvironmentManager>(::AnalysisApiEnvironmentManagerImpl.bind(testDisposable))
useAdditionalService<ApplicationDisposableProvider> { ExecutionListenerBasedDisposableProvider() }
useAdditionalService<KotlinStandardLibrariesPathProvider> { StandardLibrariesPathProviderForKotlinProject }
useCustomCompilerConfigurationProvider(::AnalysisApiTestCompilerConfiguratorProvider)
usePreAnalysisHandlers(::ProjectStructureInitialisationPreAnalysisHandler.bind(configurator))
useDirectives(AnalysisApiTestDirectives)
}
@@ -1,7 +0,0 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.test.framework.project.structure
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.test.ApplicationEnvironmentDisposer
import org.jetbrains.kotlin.test.services.TestService
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.moduleStructure
import org.jetbrains.kotlin.test.services.*
abstract class AnalysisApiEnvironmentManager : TestService {
abstract val testServices: TestServices
@@ -43,7 +40,7 @@ class AnalysisApiEnvironmentManagerImpl(
private val _projectEnvironment: KotlinCoreProjectEnvironment by lazy {
StandaloneProjectFactory.createProjectEnvironment(
testRootDisposable,
ApplicationEnvironmentDisposer.ROOT_DISPOSABLE
testServices.applicationDisposableProvider.getApplicationRootDisposable(),
)
}
@@ -66,7 +63,7 @@ class AnalysisApiEnvironmentManagerImpl(
useSiteCompilerConfiguration.get(JVMConfigurationKeys.JDK_HOME)?.toPath(),
)
testServices.compilerConfigurationProvider.registerCompilerExtensions(getProject(), useSiteModule)
testServices.compilerConfigurationProvider.registerCompilerExtensions(getProject(), useSiteModule, useSiteCompilerConfiguration)
}
override fun getProjectEnvironment(): KotlinCoreProjectEnvironment =
@@ -21,10 +21,10 @@ import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
class AnalysisApiTestCompilerConfiguratorProvider(
override val testServices: TestServices,
testServices: TestServices,
override val testRootDisposable: Disposable,
override val configurators: List<AbstractEnvironmentConfigurator>
) : CompilerConfigurationProvider() {
) : CompilerConfigurationProvider(testServices) {
private val configurationCache: MutableMap<TestModule, CompilerConfiguration> = mutableMapOf()
private val allProjectBinaryRoots by lazy {
@@ -43,7 +43,7 @@ internal object TestModuleCompiler {
JarOutputStream(librarySourcesPath.outputStream(), manifest).use { jarOutputStream ->
for (testFile in module.files) {
val text = testServices.sourceFileProvider.getContentOfSourceFile(testFile)
addFileToJar(testFile.name, text, jarOutputStream)
addFileToJar(testFile.relativePath, text, jarOutputStream)
}
}
return librarySourcesPath
@@ -46,14 +46,7 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
configureTest()
defaultConfiguration(this)
registerAnalysisApiBaseTestServices(disposable, FirLowLevelAnalysisApiTestConfigurator)
useAdditionalService<ApplicationDisposableProvider> { ExecutionListenerBasedDisposableProvider() }
useAdditionalService<KotlinStandardLibrariesPathProvider> { StandardLibrariesPathProviderForKotlinProject }
useAdditionalService(::TestKtModuleProvider)
usePreAnalysisHandlers(::ModuleRegistrarPreAnalysisHandler.bind(disposable, true))
usePreAnalysisHandlers(::SealedClassesInheritorsCaclulatorPreAnalysisHandler)
registerAnalysisApiBaseTestServices(disposable, FirLowLevelCompilerBasedTestConfigurator)
firHandlersStep {
useHandlers(::LLDiagnosticParameterChecker)
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.test.model.TestModule
import java.io.File
abstract class CompilerConfigurationProvider(val testServices: TestServices) : TestService {
abstract val testServices: TestServices
abstract val testRootDisposable: Disposable
abstract val configurators: List<AbstractEnvironmentConfigurator>
@@ -46,8 +45,8 @@ abstract class CompilerConfigurationProvider(val testServices: TestServices) : T
return getKotlinCoreEnvironment(module).project
}
fun registerCompilerExtensions(project: Project, module: TestModule) {
configurators.forEach { it.registerCompilerExtensions(project, module) }
fun registerCompilerExtensions(project: Project, module: TestModule, configuration: CompilerConfiguration) {
configurators.forEach { it.registerCompilerExtensions(project, module, configuration) }
}
open fun getPackagePartProviderFactory(module: TestModule): (GlobalSearchScope) -> JvmPackagePartProvider {
@@ -72,7 +71,7 @@ abstract class CompilerConfigurationProvider(val testServices: TestServices) : T
val TestServices.compilerConfigurationProvider: CompilerConfigurationProvider by TestServices.testServiceAccessor()
open class CompilerConfigurationProviderImpl(
override val testServices: TestServices,
testServices: TestServices,
override val testRootDisposable: Disposable,
override val configurators: List<AbstractEnvironmentConfigurator>
) : CompilerConfigurationProvider(testServices) {
@@ -101,6 +100,7 @@ open class CompilerConfigurationProviderImpl(
).also { registerCompilerExtensions(projectEnv.project, module, configuration) }
}
@OptIn(TestInfrastructureInternals::class)
fun createCompilerConfiguration(module: TestModule): CompilerConfiguration {
return createCompilerConfiguration(module, configurators)