K2: Support binary library dependencies between test modules
The test infrastructure for analysis supports binary module tests, but the binary build does not use another binary module as a dependency when it passes the class path. As a result, each binary module build does not work when they have dependency on each other. This commit fixes the issue by 1. Topological sort in the order of dependency graph for test modules. 2. Pass module paths as extra class paths when they have dependency on each other. ^KT-64994
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.cases.generated.cases.components.compilerFacility;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory;
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
|
||||||
|
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
|
||||||
|
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.compilerFacility.AbstractMultiModuleCompilerFacilityTest;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("analysis/analysis-api/testData/components/compilerFacility/compilationMultiBinaryModule")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class FirIdeNormalAnalysisLibraryBinaryModuleMultiModuleCompilerFacilityTestGenerated extends AbstractMultiModuleCompilerFacilityTest {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public AnalysisApiTestConfigurator getConfigurator() {
|
||||||
|
return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator(
|
||||||
|
new AnalysisApiTestConfiguratorFactoryData(
|
||||||
|
FrontendKind.Fir,
|
||||||
|
TestModuleKind.LibraryBinary,
|
||||||
|
AnalysisSessionMode.Normal,
|
||||||
|
AnalysisApiMode.Ide
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInCompilationMultiBinaryModule() {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/compilerFacility/compilationMultiBinaryModule"), Pattern.compile("^(.+)\\.(kt)$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("dependencyBetweenBinaryLibraries.kt")
|
||||||
|
public void testDependencyBetweenBinaryLibraries() {
|
||||||
|
runTest("analysis/analysis-api/testData/components/compilerFacility/compilationMultiBinaryModule/dependencyBetweenBinaryLibraries.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
MODULE_FRAGMENT
|
||||||
|
FILE fqName:<root> fileName:main.kt
|
||||||
|
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Int
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='public final fun test (): kotlin.Int declared in <root>'
|
||||||
|
CALL 'public final fun bar (): kotlin.Int declared in p2' type=kotlin.Int origin=null
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: p3/foo.kt
|
||||||
|
package p3;
|
||||||
|
|
||||||
|
fun foo() = 3
|
||||||
|
// MODULE: lib2(lib)
|
||||||
|
// FILE: p2/bar.kt
|
||||||
|
package p2;
|
||||||
|
|
||||||
|
fun bar() = 4 + p3.foo()
|
||||||
|
// MODULE: main(lib, lib2)
|
||||||
|
// MODULE_KIND: Source
|
||||||
|
// FILE: main.kt
|
||||||
|
import p2.bar
|
||||||
|
|
||||||
|
fun test() = bar()
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
public final class MainKt {
|
||||||
|
// source: 'main.kt'
|
||||||
|
public final static method test(): int
|
||||||
|
}
|
||||||
+2
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
|
|||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
import org.jetbrains.kotlin.test.services.sourceFileProvider
|
import org.jetbrains.kotlin.test.services.sourceFileProvider
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
object KtCodeFragmentModuleFactory : KtModuleFactory {
|
object KtCodeFragmentModuleFactory : KtModuleFactory {
|
||||||
override fun createModule(
|
override fun createModule(
|
||||||
@@ -30,6 +31,7 @@ object KtCodeFragmentModuleFactory : KtModuleFactory {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>
|
||||||
): KtModuleWithFiles {
|
): KtModuleWithFiles {
|
||||||
requireNotNull(contextModule) { "Code fragment requires a context module" }
|
requireNotNull(contextModule) { "Code fragment requires a context module" }
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.analysis.test.framework.services.libraries.compiledL
|
|||||||
import org.jetbrains.kotlin.analysis.test.framework.services.libraries.testModuleDecompiler
|
import org.jetbrains.kotlin.analysis.test.framework.services.libraries.testModuleDecompiler
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.LibraryBinary
|
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.LibraryBinary
|
||||||
@@ -23,8 +24,9 @@ object KtLibraryBinaryModuleFactory : KtModuleFactory {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
): KtModuleWithFiles {
|
): KtModuleWithFiles {
|
||||||
val library = testServices.compiledLibraryProvider.compileToLibrary(testModule).artifact
|
val library = testServices.compiledLibraryProvider.compileToLibrary(testModule, dependencyPaths).artifact
|
||||||
val decompiledFiles = testServices.testModuleDecompiler.getAllPsiFilesFromLibrary(library, project)
|
val decompiledFiles = testServices.testModuleDecompiler.getAllPsiFilesFromLibrary(library, project)
|
||||||
|
|
||||||
return KtModuleWithFiles(
|
return KtModuleWithFiles(
|
||||||
|
|||||||
+1
@@ -27,6 +27,7 @@ object KtLibrarySourceModuleFactory : KtModuleFactory {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
): KtModuleWithFiles {
|
): KtModuleWithFiles {
|
||||||
Assume.assumeFalse("Compilation of multi-platform libraries is not supported", testModule.targetPlatform.isMultiPlatform())
|
Assume.assumeFalse("Compilation of multi-platform libraries is not supported", testModule.targetPlatform.isMultiPlatform())
|
||||||
|
|
||||||
|
|||||||
+2
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.test.framework.test.configurators.moduleKin
|
|||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestService
|
import org.jetbrains.kotlin.test.services.TestService
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
fun interface KtModuleFactory : TestService {
|
fun interface KtModuleFactory : TestService {
|
||||||
/**
|
/**
|
||||||
@@ -26,6 +27,7 @@ fun interface KtModuleFactory : TestService {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
): KtModuleWithFiles
|
): KtModuleWithFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtMod
|
|||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.ScriptSource
|
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.ScriptSource
|
||||||
@@ -20,6 +21,7 @@ object KtScriptModuleFactory : KtModuleFactory {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
): KtModuleWithFiles {
|
): KtModuleWithFiles {
|
||||||
val ktFile = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project).single() as KtFile
|
val ktFile = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project).single() as KtFile
|
||||||
val module = KtScriptModuleImpl(
|
val module = KtScriptModuleImpl(
|
||||||
|
|||||||
+2
@@ -10,6 +10,7 @@ import com.intellij.psi.search.GlobalSearchScope
|
|||||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.Source
|
* @see org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind.Source
|
||||||
@@ -20,6 +21,7 @@ object KtSourceModuleFactory : KtModuleFactory {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
): KtModuleWithFiles {
|
): KtModuleWithFiles {
|
||||||
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
||||||
|
|
||||||
|
|||||||
+42
-4
@@ -42,6 +42,31 @@ private typealias LibraryCache = MutableMap<Set<Path>, KtBinaryModule>
|
|||||||
|
|
||||||
private typealias ModulesByName = Map<String, KtModuleWithFiles>
|
private typealias ModulesByName = Map<String, KtModuleWithFiles>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to run the topological sort (or post-order sort) for [TestModule]s based on the dependency graph.
|
||||||
|
* This function guarantees:
|
||||||
|
* - For [TestModule] A and B, where A has dependency on B, A will never appears earlier than B in the result list.
|
||||||
|
*/
|
||||||
|
private fun sortInDependencyPostOrder(testModules: List<TestModule>): List<TestModule> {
|
||||||
|
val namesToModules = buildMap { testModules.forEach { put(it.name, it) } }
|
||||||
|
val notVisited = testModules.toMutableSet()
|
||||||
|
val sortedModules = mutableListOf<TestModule>()
|
||||||
|
|
||||||
|
fun dfsWalk(module: TestModule) {
|
||||||
|
notVisited.remove(module)
|
||||||
|
for (dependency in module.regularDependencies) {
|
||||||
|
val dependencyAsModule = namesToModules[dependency.moduleName] ?: error("Module ${dependency.moduleName} is missing")
|
||||||
|
if (dependencyAsModule in notVisited) dfsWalk(dependencyAsModule)
|
||||||
|
}
|
||||||
|
sortedModules.add(module)
|
||||||
|
}
|
||||||
|
|
||||||
|
while (notVisited.isNotEmpty()) {
|
||||||
|
dfsWalk(notVisited.first())
|
||||||
|
}
|
||||||
|
return sortedModules
|
||||||
|
}
|
||||||
|
|
||||||
object TestModuleStructureFactory {
|
object TestModuleStructureFactory {
|
||||||
fun createProjectStructureByTestStructure(
|
fun createProjectStructureByTestStructure(
|
||||||
moduleStructure: TestModuleStructure,
|
moduleStructure: TestModuleStructure,
|
||||||
@@ -64,25 +89,38 @@ object TestModuleStructureFactory {
|
|||||||
return KtModuleProjectStructure(modules, libraryCache.values)
|
return KtModuleProjectStructure(modules, libraryCache.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to create [KtModuleWithFiles] for the given [moduleStructure]. This function guarantees:
|
||||||
|
* - For [TestModule] A and B, where A has dependency on B,
|
||||||
|
* - B will always be created earlier than A.
|
||||||
|
* - The class path of B will be given to the creation of A's module.
|
||||||
|
*
|
||||||
|
* In particular, it handles unresolved symbol issues caused by building binary libraries.
|
||||||
|
*/
|
||||||
private fun createModules(
|
private fun createModules(
|
||||||
moduleStructure: TestModuleStructure,
|
moduleStructure: TestModuleStructure,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project
|
project: Project,
|
||||||
): List<KtModuleWithFiles> {
|
): List<KtModuleWithFiles> {
|
||||||
val moduleCount = moduleStructure.modules.size
|
val modulesSortedByDependencies = sortInDependencyPostOrder(moduleStructure.modules)
|
||||||
|
val moduleCount = modulesSortedByDependencies.size
|
||||||
|
val moduleNamesToPaths = mutableMapOf<String, Collection<Path>>()
|
||||||
val existingModules = HashMap<String, KtModuleWithFiles>(moduleCount)
|
val existingModules = HashMap<String, KtModuleWithFiles>(moduleCount)
|
||||||
val result = ArrayList<KtModuleWithFiles>(moduleCount)
|
val result = ArrayList<KtModuleWithFiles>(moduleCount)
|
||||||
|
|
||||||
for (testModule in moduleStructure.modules) {
|
for (testModule in modulesSortedByDependencies) {
|
||||||
val contextModuleName = testModule.directives.singleOrZeroValue(AnalysisApiTestDirectives.CONTEXT_MODULE)
|
val contextModuleName = testModule.directives.singleOrZeroValue(AnalysisApiTestDirectives.CONTEXT_MODULE)
|
||||||
val contextModule = contextModuleName?.let(existingModules::getValue)
|
val contextModule = contextModuleName?.let(existingModules::getValue)
|
||||||
|
|
||||||
|
val dependencies = testModule.regularDependencies.mapNotNull { moduleNamesToPaths[it.moduleName] }.flatten()
|
||||||
val moduleWithFiles = testServices
|
val moduleWithFiles = testServices
|
||||||
.getKtModuleFactoryForTestModule(testModule)
|
.getKtModuleFactoryForTestModule(testModule)
|
||||||
.createModule(testModule, contextModule, testServices, project)
|
.createModule(testModule, contextModule, testServices, project, dependencies)
|
||||||
|
|
||||||
existingModules[testModule.name] = moduleWithFiles
|
existingModules[testModule.name] = moduleWithFiles
|
||||||
result.add(moduleWithFiles)
|
result.add(moduleWithFiles)
|
||||||
|
val libraryModule = moduleWithFiles.ktModule as? KtLibraryModuleImpl ?: continue
|
||||||
|
moduleNamesToPaths[testModule.name] = libraryModule.getBinaryRoots()
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
+10
-4
@@ -30,19 +30,25 @@ import java.util.jar.JarOutputStream
|
|||||||
import java.util.jar.Manifest
|
import java.util.jar.Manifest
|
||||||
import kotlin.io.path.div
|
import kotlin.io.path.div
|
||||||
import kotlin.io.path.outputStream
|
import kotlin.io.path.outputStream
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
abstract class CliTestModuleCompiler : TestModuleCompiler() {
|
abstract class CliTestModuleCompiler : TestModuleCompiler() {
|
||||||
internal abstract val compilerKind: CompilerExecutor.CompilerKind
|
internal abstract val compilerKind: CompilerExecutor.CompilerKind
|
||||||
|
|
||||||
protected abstract fun buildPlatformCompilerOptions(module: TestModule, testServices: TestServices): List<String>
|
protected abstract fun buildPlatformCompilerOptions(module: TestModule, testServices: TestServices): List<String>
|
||||||
|
|
||||||
override fun compile(tmpDir: Path, module: TestModule, testServices: TestServices): Path = CompilerExecutor.compileLibrary(
|
override fun compile(
|
||||||
|
tmpDir: Path,
|
||||||
|
module: TestModule,
|
||||||
|
testServices: TestServices,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
|
): Path = CompilerExecutor.compileLibrary(
|
||||||
compilerKind,
|
compilerKind,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
buildCompilerOptions(module, testServices),
|
buildCompilerOptions(module, testServices),
|
||||||
compilationErrorExpected = Directives.COMPILATION_ERRORS in module.directives,
|
compilationErrorExpected = Directives.COMPILATION_ERRORS in module.directives,
|
||||||
libraryName = module.name,
|
libraryName = module.name,
|
||||||
extraClasspath = buildExtraClasspath(module, testServices),
|
extraClasspath = buildExtraClasspath(module, testServices) + dependencyPaths.map { it.pathString },
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun compileTestModuleToLibrarySources(module: TestModule, testServices: TestServices): Path {
|
override fun compileTestModuleToLibrarySources(module: TestModule, testServices: TestServices): Path {
|
||||||
@@ -145,8 +151,8 @@ class DispatchingTestModuleCompiler : TestModuleCompiler() {
|
|||||||
CompilerExecutor.CompilerKind.JS to JsKlibTestModuleCompiler(),
|
CompilerExecutor.CompilerKind.JS to JsKlibTestModuleCompiler(),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun compile(tmpDir: Path, module: TestModule, testServices: TestServices): Path {
|
override fun compile(tmpDir: Path, module: TestModule, testServices: TestServices, dependencyPaths: Collection<Path>): Path {
|
||||||
return getCompiler(module).compileTestModuleToLibrary(module, testServices)
|
return getCompiler(module).compileTestModuleToLibrary(module, testServices, dependencyPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun compileTestModuleToLibrarySources(module: TestModule, testServices: TestServices): Path {
|
override fun compileTestModuleToLibrarySources(module: TestModule, testServices: TestServices): Path {
|
||||||
|
|||||||
+2
-2
@@ -13,11 +13,11 @@ import java.nio.file.Path
|
|||||||
class CompiledLibraryProvider(private val testServices: TestServices) : TestService {
|
class CompiledLibraryProvider(private val testServices: TestServices) : TestService {
|
||||||
private val libraries = mutableMapOf<String, CompiledLibrary>()
|
private val libraries = mutableMapOf<String, CompiledLibrary>()
|
||||||
|
|
||||||
fun compileToLibrary(module: TestModule): CompiledLibrary {
|
fun compileToLibrary(module: TestModule, dependencyPaths: Collection<Path> = emptyList()): CompiledLibrary {
|
||||||
if (module.name in libraries) {
|
if (module.name in libraries) {
|
||||||
error("Library for module ${module.name} is already compiled")
|
error("Library for module ${module.name} is already compiled")
|
||||||
}
|
}
|
||||||
val libraryJar = testServices.testModuleCompiler.compileTestModuleToLibrary(module, testServices)
|
val libraryJar = testServices.testModuleCompiler.compileTestModuleToLibrary(module, testServices, dependencyPaths)
|
||||||
val librarySourcesJar = testServices.testModuleCompiler.compileTestModuleToLibrarySources(module, testServices)
|
val librarySourcesJar = testServices.testModuleCompiler.compileTestModuleToLibrarySources(module, testServices)
|
||||||
|
|
||||||
return CompiledLibrary(libraryJar, librarySourcesJar).also { libraries[module.name] = it }
|
return CompiledLibrary(libraryJar, librarySourcesJar).also { libraries[module.name] = it }
|
||||||
|
|||||||
+8
-3
@@ -18,7 +18,7 @@ import kotlin.io.path.div
|
|||||||
import kotlin.io.path.writeText
|
import kotlin.io.path.writeText
|
||||||
|
|
||||||
abstract class TestModuleCompiler : TestService {
|
abstract class TestModuleCompiler : TestService {
|
||||||
fun compileTestModuleToLibrary(module: TestModule, testServices: TestServices): Path {
|
fun compileTestModuleToLibrary(module: TestModule, testServices: TestServices, dependencyPaths: Collection<Path> = emptyList()): Path {
|
||||||
val tmpDir = KtTestUtil.tmpDir("testSourcesToCompile").toPath()
|
val tmpDir = KtTestUtil.tmpDir("testSourcesToCompile").toPath()
|
||||||
for (testFile in module.files) {
|
for (testFile in module.files) {
|
||||||
val text = testServices.sourceFileProvider.getContentOfSourceFile(testFile)
|
val text = testServices.sourceFileProvider.getContentOfSourceFile(testFile)
|
||||||
@@ -28,10 +28,15 @@ abstract class TestModuleCompiler : TestService {
|
|||||||
val tmpSourceFile = filePath.createFile()
|
val tmpSourceFile = filePath.createFile()
|
||||||
tmpSourceFile.writeText(text)
|
tmpSourceFile.writeText(text)
|
||||||
}
|
}
|
||||||
return compile(tmpDir, module, testServices)
|
return compile(tmpDir, module, testServices, dependencyPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun compile(tmpDir: Path, module: TestModule, testServices: TestServices): Path
|
abstract fun compile(
|
||||||
|
tmpDir: Path,
|
||||||
|
module: TestModule,
|
||||||
|
testServices: TestServices,
|
||||||
|
dependencyPaths: Collection<Path> = emptyList(),
|
||||||
|
): Path
|
||||||
|
|
||||||
abstract fun compileTestModuleToLibrarySources(module: TestModule, testServices: TestServices): Path?
|
abstract fun compileTestModuleToLibrarySources(module: TestModule, testServices: TestServices): Path?
|
||||||
|
|
||||||
|
|||||||
+2
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.test.getAnalyzerServices
|
|||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestModuleStructure
|
import org.jetbrains.kotlin.test.services.TestModuleStructure
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
object AnalysisApiFirOutOfContentRootTestConfigurator : AnalysisApiFirSourceLikeTestConfigurator(false) {
|
object AnalysisApiFirOutOfContentRootTestConfigurator : AnalysisApiFirSourceLikeTestConfigurator(false) {
|
||||||
override val testPrefix: String
|
override val testPrefix: String
|
||||||
@@ -68,6 +69,7 @@ private object KtOutOfContentRootModuleFactory : KtModuleFactory {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
): KtModuleWithFiles {
|
): KtModuleWithFiles {
|
||||||
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
val psiFiles = TestModuleStructureFactory.createSourcePsiFiles(testModule, testServices, project)
|
||||||
val platform = testModule.targetPlatform
|
val platform = testModule.targetPlatform
|
||||||
|
|||||||
+2
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
|||||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
import org.jetbrains.kotlin.test.services.TestServices
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
object AnalysisApiFirStdlibSourceTestConfigurator : AnalysisApiFirSourceLikeTestConfigurator(false) {
|
object AnalysisApiFirStdlibSourceTestConfigurator : AnalysisApiFirSourceLikeTestConfigurator(false) {
|
||||||
override fun configureTest(builder: TestConfigurationBuilder, disposable: Disposable) {
|
override fun configureTest(builder: TestConfigurationBuilder, disposable: Disposable) {
|
||||||
@@ -30,6 +31,7 @@ private object KtStdlibSourceModuleFactory : KtModuleFactory {
|
|||||||
contextModule: KtModuleWithFiles?,
|
contextModule: KtModuleWithFiles?,
|
||||||
testServices: TestServices,
|
testServices: TestServices,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
dependencyPaths: Collection<Path>,
|
||||||
): KtModuleWithFiles {
|
): KtModuleWithFiles {
|
||||||
val libraryJar = ForTestCompileRuntime.runtimeJarForTests().toPath()
|
val libraryJar = ForTestCompileRuntime.runtimeJarForTests().toPath()
|
||||||
val librarySourcesJar = ForTestCompileRuntime.runtimeSourcesJarForTests().toPath()
|
val librarySourcesJar = ForTestCompileRuntime.runtimeSourcesJarForTests().toPath()
|
||||||
|
|||||||
+6
-2
@@ -100,18 +100,22 @@ internal fun AnalysisApiTestGroup.generateAnalysisApiTests() {
|
|||||||
|
|
||||||
component(
|
component(
|
||||||
"compilerFacility",
|
"compilerFacility",
|
||||||
filter = testModuleKindIs(TestModuleKind.Source, TestModuleKind.LibrarySource)
|
filter = testModuleKindIs(TestModuleKind.Source, TestModuleKind.LibrarySource, TestModuleKind.LibraryBinary)
|
||||||
and frontendIs(FrontendKind.Fir)
|
and frontendIs(FrontendKind.Fir)
|
||||||
and analysisSessionModeIs(AnalysisSessionMode.Normal)
|
and analysisSessionModeIs(AnalysisSessionMode.Normal)
|
||||||
and analysisApiModeIs(AnalysisApiMode.Ide)
|
and analysisApiModeIs(AnalysisApiMode.Ide)
|
||||||
) {
|
) {
|
||||||
test(AbstractCompilerFacilityTest::class) {
|
test(AbstractCompilerFacilityTest::class, filter = testModuleKindIs(TestModuleKind.Source, TestModuleKind.LibrarySource)) {
|
||||||
model("compilation", pattern = TestGeneratorUtil.KT)
|
model("compilation", pattern = TestGeneratorUtil.KT)
|
||||||
}
|
}
|
||||||
|
|
||||||
test(AbstractMultiModuleCompilerFacilityTest::class, filter = testModuleKindIs(TestModuleKind.Source)) {
|
test(AbstractMultiModuleCompilerFacilityTest::class, filter = testModuleKindIs(TestModuleKind.Source)) {
|
||||||
model("compilationMultiModule", pattern = TestGeneratorUtil.KT)
|
model("compilationMultiModule", pattern = TestGeneratorUtil.KT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test(AbstractMultiModuleCompilerFacilityTest::class, filter = testModuleKindIs(TestModuleKind.LibraryBinary)) {
|
||||||
|
model("compilationMultiBinaryModule", pattern = TestGeneratorUtil.KT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group(filter = testModuleKindIs(TestModuleKind.Source, TestModuleKind.ScriptSource)) {
|
group(filter = testModuleKindIs(TestModuleKind.Source, TestModuleKind.ScriptSource)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user