blob: e7383183fa47b342e7c0ea6d8efcb999e04aa02f [file] [log] [blame]
/*
* Copyright 2010-2020 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.test.services
import org.jetbrains.kotlin.codeMetaInfo.CodeMetaInfoParser
import org.jetbrains.kotlin.codeMetaInfo.CodeMetaInfoRenderer
import org.jetbrains.kotlin.codeMetaInfo.model.CodeMetaInfo
import org.jetbrains.kotlin.codeMetaInfo.model.ParsedCodeMetaInfo
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
class GlobalMetadataInfoHandler(
private val testServices: TestServices,
private val processors: List<AdditionalMetaInfoProcessor>
) : TestService {
private lateinit var existingInfosPerFile: Map<TestFile, List<ParsedCodeMetaInfo>>
private val infosPerFile: MutableMap<TestFile, MutableList<CodeMetaInfo>> =
mutableMapOf<TestFile, MutableList<CodeMetaInfo>>().withDefault { mutableListOf() }
private val existingInfosPerFilePerInfoCache = mutableMapOf<Pair<TestFile, CodeMetaInfo>, List<ParsedCodeMetaInfo>>()
@OptIn(ExperimentalStdlibApi::class)
fun parseExistingMetadataInfosFromAllSources() {
existingInfosPerFile = buildMap {
for (file in testServices.moduleStructure.modules.flatMap { it.files }) {
put(file, CodeMetaInfoParser.getCodeMetaInfoFromText(file.originalContent))
}
}
}
fun getExistingMetaInfosForFile(file: TestFile): List<ParsedCodeMetaInfo> {
return existingInfosPerFile.getValue(file)
}
fun getReportedMetaInfosForFile(file: TestFile): List<CodeMetaInfo> {
return infosPerFile.getValue(file)
}
fun getExistingMetaInfosForActualMetadata(file: TestFile, metaInfo: CodeMetaInfo): List<ParsedCodeMetaInfo> {
return existingInfosPerFilePerInfoCache.getOrPut(file to metaInfo) {
getExistingMetaInfosForFile(file).filter { it == metaInfo }
}
}
fun addMetadataInfosForFile(file: TestFile, codeMetaInfos: List<CodeMetaInfo>) {
val infos = infosPerFile.getOrPut(file) { mutableListOf() }
infos += codeMetaInfos
}
fun compareAllMetaDataInfos() {
// TODO: adapt to multiple testdata files
val moduleStructure = testServices.moduleStructure
val builder = StringBuilder()
for (module in moduleStructure.modules) {
for (file in module.files) {
if (file.isAdditional) continue
processors.forEach { it.processMetaInfos(module, file) }
val codeMetaInfos = infosPerFile.getValue(file)
val fileBuilder = StringBuilder()
CodeMetaInfoRenderer.renderTagsToText(
fileBuilder,
codeMetaInfos,
testServices.sourceFileProvider.getContentOfSourceFile(file)
)
val reverseTransformers = testServices.sourceFileProvider.preprocessors.filterIsInstance<ReversibleSourceFilePreprocessor>()
val initialFileContent = fileBuilder.stripAdditionalEmptyLines(file).toString()
val actualFileContent =
reverseTransformers.foldRight(initialFileContent) { transformer, source -> transformer.revert(file, source) }
builder.append(actualFileContent)
}
}
val actualText = builder.toString()
testServices.assertions.assertEqualsToFile(moduleStructure.originalTestDataFiles.single(), actualText)
}
private fun StringBuilder.stripAdditionalEmptyLines(file: TestFile): CharSequence {
return if (file.startLineNumberInOriginalFile != 0) {
this.removePrefix((1..file.startLineNumberInOriginalFile).joinToString(separator = "") { "\n" })
} else {
this.toString()
}
}
}
val TestServices.globalMetadataInfoHandler: GlobalMetadataInfoHandler by TestServices.testServiceAccessor()
abstract class AdditionalMetaInfoProcessor(protected val testServices: TestServices) {
protected val globalMetadataInfoHandler: GlobalMetadataInfoHandler
get() = testServices.globalMetadataInfoHandler
abstract fun processMetaInfos(module: TestModule, file: TestFile)
}