[AA] Tests: Remove topological ordering from KtTestModule creation
- The test infrastructure already requires test modules to be properly ordered regarding dependencies, so a module A which is a dependency for a module B must always be ordered before B. Hence, it makes no sense to also order modules topologically. - Reordering modules may cause the resulting `KtTestModule`s to be out-of-order with the test modules, because the topological order might be different from the test module order, even if the dependency relationship already holds in the original order. `KtTestModuleProjectStructure` requires the same ordering as test modules to ensure the same order during iteration of `KtTestModule`s. ^KT-65960 ^KT-64994
This commit is contained in:
committed by
Space Team
parent
c7ccfcc785
commit
5663521a36
+2
-2
@@ -20,8 +20,8 @@ fun interface KtModuleFactory : TestService {
|
|||||||
* @param contextModule a module to use as a context module. Some kinds of modules (such as dangling file modules) require a
|
* @param contextModule a module to use as a context module. Some kinds of modules (such as dangling file modules) require a
|
||||||
* context module. Modules representing code fragments also require a context element. That is why the [KtTestModule] is passed
|
* context module. Modules representing code fragments also require a context element. That is why the [KtTestModule] is passed
|
||||||
* instead of a plain [KtModule][org.jetbrains.kotlin.analysis.project.structure.KtModule].
|
* instead of a plain [KtModule][org.jetbrains.kotlin.analysis.project.structure.KtModule].
|
||||||
*
|
* @param dependencyPaths The binary roots of [testModule]'s binary library dependencies. This allows avoiding unresolved symbol issues
|
||||||
* @param dependencyPaths Paths of directories containing dependency libraries. The paths will be set as class paths for compilation.
|
* when compiling test binary libraries that depend on other test binary libraries.
|
||||||
*/
|
*/
|
||||||
fun createModule(
|
fun createModule(
|
||||||
testModule: TestModule,
|
testModule: TestModule,
|
||||||
|
|||||||
+17
-51
@@ -12,6 +12,7 @@ import com.intellij.psi.search.GlobalSearchScope
|
|||||||
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
|
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule
|
||||||
|
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
|
||||||
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
|
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
|
||||||
@@ -40,31 +41,6 @@ private typealias LibraryCache = MutableMap<Set<Path>, KtBinaryModule>
|
|||||||
|
|
||||||
private typealias ModulesByName = Map<String, KtTestModule>
|
private typealias ModulesByName = Map<String, KtTestModule>
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 = testModules.associateBy { it.name }
|
|
||||||
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,
|
||||||
@@ -86,14 +62,10 @@ object TestModuleStructureFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function to create [KtModuleWithFiles] for the given [moduleStructure].
|
* The test infrastructure ensures that the given [moduleStructure] contains properly ordered dependencies: a [TestModule] can only
|
||||||
|
* depend on test modules which precede it. Hence, this function does not need to order dependencies itself.
|
||||||
*
|
*
|
||||||
* This function guarantees:
|
* @return A list of [KtTestModule]s in the same order as [TestModuleStructure.modules].
|
||||||
* - 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,
|
||||||
@@ -101,30 +73,24 @@ object TestModuleStructureFactory {
|
|||||||
project: Project,
|
project: Project,
|
||||||
): List<KtTestModule> {
|
): List<KtTestModule> {
|
||||||
val moduleCount = moduleStructure.modules.size
|
val moduleCount = moduleStructure.modules.size
|
||||||
|
val existingModules = HashMap<String, KtTestModule>(moduleCount)
|
||||||
val result = ArrayList<KtTestModule>(moduleCount)
|
val result = ArrayList<KtTestModule>(moduleCount)
|
||||||
|
|
||||||
val processedModules = HashMap<String, KtTestModule>(moduleCount)
|
for (testModule in moduleStructure.modules) {
|
||||||
val processedDependencies = mutableMapOf<String, Collection<Path>>()
|
|
||||||
|
|
||||||
for (testModule in sortInDependencyPostOrder(moduleStructure.modules)) {
|
|
||||||
val contextModuleName = testModule.directives.singleOrZeroValue(AnalysisApiTestDirectives.CONTEXT_MODULE)
|
val contextModuleName = testModule.directives.singleOrZeroValue(AnalysisApiTestDirectives.CONTEXT_MODULE)
|
||||||
val contextModule = contextModuleName?.let(processedModules::getValue)
|
val contextModule = contextModuleName?.let(existingModules::getValue)
|
||||||
|
|
||||||
val dependencyPaths = testModule.regularDependencies
|
val dependencyBinaryRoots = testModule.regularDependencies.flatMap { dependency ->
|
||||||
.mapNotNull { processedDependencies[it.moduleName] }
|
val libraryModule = existingModules.getValue(dependency.moduleName).ktModule as? KtLibraryModule
|
||||||
.flatten()
|
libraryModule?.getBinaryRoots().orEmpty()
|
||||||
|
|
||||||
val moduleWithFiles = testServices
|
|
||||||
.getKtModuleFactoryForTestModule(testModule)
|
|
||||||
.createModule(testModule, contextModule, dependencyPaths, testServices, project)
|
|
||||||
|
|
||||||
processedModules[testModule.name] = moduleWithFiles
|
|
||||||
result.add(moduleWithFiles)
|
|
||||||
|
|
||||||
val libraryModule = moduleWithFiles.ktModule
|
|
||||||
if (libraryModule is KtLibraryModuleImpl) {
|
|
||||||
processedDependencies[testModule.name] = libraryModule.getBinaryRoots()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ktTestModule = testServices
|
||||||
|
.getKtModuleFactoryForTestModule(testModule)
|
||||||
|
.createModule(testModule, contextModule, dependencyBinaryRoots, testServices, project)
|
||||||
|
|
||||||
|
existingModules[testModule.name] = ktTestModule
|
||||||
|
result.add(ktTestModule)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
Reference in New Issue
Block a user