[Native][tests] Dump the list of all available tests during compilation
^KT-50316
This commit is contained in:
@@ -386,6 +386,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
putIfNotNull(RUNTIME_LOGS, arguments.runtimeLogs)
|
putIfNotNull(RUNTIME_LOGS, arguments.runtimeLogs)
|
||||||
putIfNotNull(BUNDLE_ID, parseBundleId(arguments, outputKind, configuration))
|
putIfNotNull(BUNDLE_ID, parseBundleId(arguments, outputKind, configuration))
|
||||||
put(MEANINGFUL_BRIDGE_NAMES, arguments.meaningfulBridgeNames)
|
put(MEANINGFUL_BRIDGE_NAMES, arguments.meaningfulBridgeNames)
|
||||||
|
arguments.testDumpOutputPath?.let { put(TEST_DUMP_OUTPUT_PATH, it) }
|
||||||
put(PARTIAL_LINKAGE, arguments.partialLinkage)
|
put(PARTIAL_LINKAGE, arguments.partialLinkage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -361,6 +361,13 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
@Argument(value = "-Xmeaningful-bridge-names", description = "(Unstable) Produce meaningful names for reverse bridges. Useful only for compiler tests.")
|
@Argument(value = "-Xmeaningful-bridge-names", description = "(Unstable) Produce meaningful names for reverse bridges. Useful only for compiler tests.")
|
||||||
var meaningfulBridgeNames: Boolean = false
|
var meaningfulBridgeNames: Boolean = false
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
value = "-Xdump-tests-to",
|
||||||
|
valueDescription = "<path>",
|
||||||
|
description = "Path to a file to dump the list of all available tests"
|
||||||
|
)
|
||||||
|
var testDumpOutputPath: String? = null
|
||||||
|
|
||||||
@Argument(value = "-Xlazy-ir-for-caches", valueDescription = "{disable|enable}", description = "Use lazy IR for cached libraries")
|
@Argument(value = "-Xlazy-ir-for-caches", valueDescription = "{disable|enable}", description = "Use lazy IR for cached libraries")
|
||||||
var lazyIrForCaches: String? = null
|
var lazyIrForCaches: String? = null
|
||||||
|
|
||||||
|
|||||||
+4
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.konan.target.KonanTarget
|
|||||||
import org.jetbrains.kotlin.library.SerializedIrModule
|
import org.jetbrains.kotlin.library.SerializedIrModule
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||||
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
|
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
|
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
|
||||||
|
|
||||||
@@ -290,6 +291,9 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
getLocalClassName(source)?.let { name -> putLocalClassName(destination, name) }
|
getLocalClassName(source)?.let { name -> putLocalClassName(destination, name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test suite class -> test function names */
|
||||||
|
val testCasesToDump = mutableMapOf<ClassId, MutableCollection<String>>()
|
||||||
|
|
||||||
val reflectionTypes: KonanReflectionTypes by lazy(PUBLICATION) {
|
val reflectionTypes: KonanReflectionTypes by lazy(PUBLICATION) {
|
||||||
KonanReflectionTypes(moduleDescriptor)
|
KonanReflectionTypes(moduleDescriptor)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -327,6 +327,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
|
|
||||||
internal val unitSuspendFunctionObjCExport: UnitSuspendFunctionObjCExport
|
internal val unitSuspendFunctionObjCExport: UnitSuspendFunctionObjCExport
|
||||||
get() = configuration.get(BinaryOptions.unitSuspendFunctionObjCExport) ?: UnitSuspendFunctionObjCExport.LEGACY
|
get() = configuration.get(BinaryOptions.unitSuspendFunctionObjCExport) ?: UnitSuspendFunctionObjCExport.LEGACY
|
||||||
|
|
||||||
|
internal val testDumpFile: File? = configuration[KonanConfigKeys.TEST_DUMP_OUTPUT_PATH]?.let(::File)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String)
|
fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String)
|
||||||
|
|||||||
+2
@@ -172,6 +172,8 @@ class KonanConfigKeys {
|
|||||||
val LAZY_IR_FOR_CACHES: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("use lazy IR for cached libraries")
|
val LAZY_IR_FOR_CACHES: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("use lazy IR for cached libraries")
|
||||||
val MEANINGFUL_BRIDGE_NAMES: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("enable meaningful bridge names")
|
val MEANINGFUL_BRIDGE_NAMES: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("enable meaningful bridge names")
|
||||||
val PARTIAL_LINKAGE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("allows some symbols in klibs be missed")
|
val PARTIAL_LINKAGE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("allows some symbols in klibs be missed")
|
||||||
|
val TEST_DUMP_OUTPUT_PATH: CompilerConfigurationKey<String?> = CompilerConfigurationKey.create("path to a file to dump the list of all available tests")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
@@ -348,6 +348,30 @@ internal val dependenciesLowerPhase = NamedCompilerPhase(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
internal val dumpTestsPhase = makeCustomPhase<Context, IrModuleFragment>(
|
||||||
|
name = "dumpTestsPhase",
|
||||||
|
description = "Dump the list of all available tests",
|
||||||
|
op = { context, _ ->
|
||||||
|
val testDumpFile = context.config.testDumpFile
|
||||||
|
requireNotNull(testDumpFile)
|
||||||
|
|
||||||
|
if (context.testCasesToDump.isEmpty()) {
|
||||||
|
testDumpFile.writeText("")
|
||||||
|
return@makeCustomPhase
|
||||||
|
}
|
||||||
|
|
||||||
|
testDumpFile.writeText(
|
||||||
|
context.testCasesToDump.asSequence()
|
||||||
|
.flatMap { (suiteClassId, functionNames) ->
|
||||||
|
val suiteName = suiteClassId.asString()
|
||||||
|
functionNames.asSequence().map { "$suiteName:$it" }
|
||||||
|
}
|
||||||
|
.sorted()
|
||||||
|
.joinToString(separator = "\n")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
internal val entryPointPhase = makeCustomPhase<Context, IrModuleFragment>(
|
internal val entryPointPhase = makeCustomPhase<Context, IrModuleFragment>(
|
||||||
name = "addEntryPoint",
|
name = "addEntryPoint",
|
||||||
description = "Add entry point for program",
|
description = "Add entry point for program",
|
||||||
@@ -533,6 +557,7 @@ private val backendCodegen = namedUnitPhase(
|
|||||||
allLoweringsPhase then // Lower current module first.
|
allLoweringsPhase then // Lower current module first.
|
||||||
dependenciesLowerPhase then // Then lower all libraries in topological order.
|
dependenciesLowerPhase then // Then lower all libraries in topological order.
|
||||||
// With that we guarantee that inline functions are unlowered while being inlined.
|
// With that we guarantee that inline functions are unlowered while being inlined.
|
||||||
|
dumpTestsPhase then
|
||||||
entryPointPhase then
|
entryPointPhase then
|
||||||
exportInternalAbiPhase then
|
exportInternalAbiPhase then
|
||||||
useInternalAbiPhase then
|
useInternalAbiPhase then
|
||||||
@@ -602,6 +627,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
|||||||
disableUnless(objectFilesPhase, config.produce.involvesLinkStage)
|
disableUnless(objectFilesPhase, config.produce.involvesLinkStage)
|
||||||
disableUnless(linkerPhase, config.produce.involvesLinkStage)
|
disableUnless(linkerPhase, config.produce.involvesLinkStage)
|
||||||
disableIf(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) == TestRunnerKind.NONE)
|
disableIf(testProcessorPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) == TestRunnerKind.NONE)
|
||||||
|
disableIf(dumpTestsPhase, getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) == TestRunnerKind.NONE || config.testDumpFile == null)
|
||||||
disableUnless(buildDFGPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
disableUnless(buildDFGPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
||||||
disableUnless(devirtualizationAnalysisPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
disableUnless(devirtualizationAnalysisPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
||||||
disableUnless(devirtualizationPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
disableUnless(devirtualizationPhase, getBoolean(KonanConfigKeys.OPTIMIZATION))
|
||||||
|
|||||||
+54
-32
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.ir.util.addChild
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
@@ -71,13 +72,6 @@ internal class TestProcessor (val context: Context) {
|
|||||||
private val IrFile.fileName
|
private val IrFile.fileName
|
||||||
get() = name.substringAfterLast('/')
|
get() = name.substringAfterLast('/')
|
||||||
|
|
||||||
private val IrFile.topLevelSuiteName: String
|
|
||||||
get() {
|
|
||||||
val packageFqName = fqName
|
|
||||||
val shortFileName = PackagePartClassUtils.getFilePartShortName(fileName)
|
|
||||||
return if (packageFqName.isRoot) shortFileName else "$packageFqName.$shortFileName"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MutableList<TestFunction>.registerFunction(
|
private fun MutableList<TestFunction>.registerFunction(
|
||||||
function: IrFunction,
|
function: IrFunction,
|
||||||
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) =
|
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) =
|
||||||
@@ -101,7 +95,7 @@ internal class TestProcessor (val context: Context) {
|
|||||||
// Call registerTestCase(name: String, testFunction: () -> Unit) method.
|
// Call registerTestCase(name: String, testFunction: () -> Unit) method.
|
||||||
+irCall(registerTestCase).apply {
|
+irCall(registerTestCase).apply {
|
||||||
dispatchReceiver = irGet(receiver)
|
dispatchReceiver = irGet(receiver)
|
||||||
putValueArgument(0, irString(it.function.name.identifier))
|
putValueArgument(0, irString(it.functionName))
|
||||||
putValueArgument(1, IrFunctionReferenceImpl(
|
putValueArgument(1, IrFunctionReferenceImpl(
|
||||||
it.function.startOffset,
|
it.function.startOffset,
|
||||||
it.function.endOffset,
|
it.function.endOffset,
|
||||||
@@ -159,19 +153,19 @@ internal class TestProcessor (val context: Context) {
|
|||||||
private fun IrType.isTestFunctionKind() = classifierOrNull == symbols.testFunctionKind
|
private fun IrType.isTestFunctionKind() = classifierOrNull == symbols.testFunctionKind
|
||||||
|
|
||||||
private data class TestFunction(
|
private data class TestFunction(
|
||||||
val function: IrFunction,
|
val function: IrFunction,
|
||||||
val kind: FunctionKind,
|
val kind: FunctionKind,
|
||||||
val ignored: Boolean
|
val ignored: Boolean
|
||||||
)
|
) {
|
||||||
|
val functionName: String get() = function.name.identifier
|
||||||
|
}
|
||||||
|
|
||||||
private inner class TestClass(val ownerClass: IrClass) {
|
private inner class TestClass(val ownerClass: IrClass) {
|
||||||
var companion: IrClass? = null
|
var companion: IrClass? = null
|
||||||
val functions = mutableListOf<TestFunction>()
|
val functions = mutableListOf<TestFunction>()
|
||||||
|
|
||||||
fun registerFunction(
|
val suiteClassId: ClassId = ownerClass.classId ?: error(ownerClass.render())
|
||||||
function: IrFunction,
|
val suiteName: String get() = suiteClassId.asFqNameString()
|
||||||
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>
|
|
||||||
) = functions.registerFunction(function, kinds)
|
|
||||||
|
|
||||||
fun registerFunction(function: IrFunction, kind: FunctionKind, ignored: Boolean) =
|
fun registerFunction(function: IrFunction, kind: FunctionKind, ignored: Boolean) =
|
||||||
functions.registerFunction(function, kind, ignored)
|
functions.registerFunction(function, kind, ignored)
|
||||||
@@ -179,7 +173,12 @@ internal class TestProcessor (val context: Context) {
|
|||||||
|
|
||||||
private inner class AnnotationCollector(val irFile: IrFile) : IrElementVisitorVoid {
|
private inner class AnnotationCollector(val irFile: IrFile) : IrElementVisitorVoid {
|
||||||
val testClasses = mutableMapOf<IrClass, TestClass>()
|
val testClasses = mutableMapOf<IrClass, TestClass>()
|
||||||
|
|
||||||
val topLevelFunctions = mutableListOf<TestFunction>()
|
val topLevelFunctions = mutableListOf<TestFunction>()
|
||||||
|
val topLevelSuiteClassId: ClassId by lazy {
|
||||||
|
ClassId(irFile.fqName, PackagePartClassUtils.getFilePartShortName(irFile.fileName).let(Name::identifier))
|
||||||
|
}
|
||||||
|
val topLevelSuiteName: String get() = topLevelSuiteClassId.asFqNameString()
|
||||||
|
|
||||||
private fun MutableMap<IrClass, TestClass>.getTestClass(key: IrClass) =
|
private fun MutableMap<IrClass, TestClass>.getTestClass(key: IrClass) =
|
||||||
getOrPut(key) { TestClass(key) }
|
getOrPut(key) { TestClass(key) }
|
||||||
@@ -474,10 +473,12 @@ internal class TestProcessor (val context: Context) {
|
|||||||
* Builds a test suite class representing a test class (any class in the original IrFile with method(s)
|
* Builds a test suite class representing a test class (any class in the original IrFile with method(s)
|
||||||
* annotated with @Test). The test suite class is a subclass of ClassTestSuite<T> where T is the test class.
|
* annotated with @Test). The test suite class is a subclass of ClassTestSuite<T> where T is the test class.
|
||||||
*/
|
*/
|
||||||
private fun buildClassSuite(testClass: IrClass,
|
private fun buildClassSuite(
|
||||||
testCompanion: IrClass?,
|
suiteName: String,
|
||||||
functions: Collection<TestFunction>,
|
testClass: IrClass,
|
||||||
irFile: IrFile
|
testCompanion: IrClass?,
|
||||||
|
functions: Collection<TestFunction>,
|
||||||
|
irFile: IrFile
|
||||||
): IrClass {
|
): IrClass {
|
||||||
return IrClassImpl(
|
return IrClassImpl(
|
||||||
testClass.startOffset, testClass.endOffset,
|
testClass.startOffset, testClass.endOffset,
|
||||||
@@ -506,8 +507,7 @@ internal class TestProcessor (val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val constructor = buildClassSuiteConstructor(
|
val constructor = buildClassSuiteConstructor(
|
||||||
testClass.fqNameForIrSerialization.toString(), testClassType, testCompanionType,
|
suiteName, testClassType, testCompanionType, symbol, this, functions, testClass.ignored
|
||||||
symbol, this, functions, testClass.ignored
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val instanceGetter: IrFunction
|
val instanceGetter: IrFunction
|
||||||
@@ -535,19 +535,19 @@ internal class TestProcessor (val context: Context) {
|
|||||||
|
|
||||||
// region IR generation methods
|
// region IR generation methods
|
||||||
private fun generateClassSuite(irFile: IrFile, testClass: TestClass) =
|
private fun generateClassSuite(irFile: IrFile, testClass: TestClass) =
|
||||||
with(buildClassSuite(testClass.ownerClass, testClass.companion, testClass.functions, irFile)) {
|
with(buildClassSuite(testClass.suiteName, testClass.ownerClass, testClass.companion, testClass.functions, irFile)) {
|
||||||
val irConstructor = constructors.single()
|
val irConstructor = constructors.single()
|
||||||
val irBuilder = context.createIrBuilder(irFile.symbol, testClass.ownerClass.startOffset, testClass.ownerClass.endOffset)
|
val irBuilder = context.createIrBuilder(irFile.symbol, testClass.ownerClass.startOffset, testClass.ownerClass.endOffset)
|
||||||
irBuilder.irCall(irConstructor)
|
irBuilder.irCall(irConstructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if this fqName already used or not. */
|
/** Check if this fqName already used or not. */
|
||||||
private fun checkSuiteName(irFile: IrFile, name: String): Boolean {
|
private fun checkTopLevelSuiteName(irFile: IrFile, topLevelSuiteName: String): Boolean {
|
||||||
if (topLevelSuiteNames.contains(name)) {
|
if (topLevelSuiteNames.contains(topLevelSuiteName)) {
|
||||||
context.reportCompilationError("Package '${irFile.fqName}' has top-level test " +
|
context.reportCompilationError("Package '${irFile.fqName}' has top-level test " +
|
||||||
"functions in several files with the same name: '${irFile.fileName}'")
|
"functions in several files with the same name: '${irFile.fileName}'")
|
||||||
}
|
}
|
||||||
topLevelSuiteNames.add(name)
|
topLevelSuiteNames.add(topLevelSuiteName)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,16 +570,15 @@ internal class TestProcessor (val context: Context) {
|
|||||||
&& it.valueParameters[2].type.isBoolean()
|
&& it.valueParameters[2].type.isBoolean()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateTopLevelSuite(irFile: IrFile, functions: Collection<TestFunction>): IrExpression? {
|
private fun generateTopLevelSuite(irFile: IrFile, topLevelSuiteName: String, functions: Collection<TestFunction>): IrExpression? {
|
||||||
val irBuilder = context.createIrBuilder(irFile.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET)
|
val irBuilder = context.createIrBuilder(irFile.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET)
|
||||||
val suiteName = irFile.topLevelSuiteName
|
if (!checkTopLevelSuiteName(irFile, topLevelSuiteName)) {
|
||||||
if (!checkSuiteName(irFile, suiteName)) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return irBuilder.irBlock {
|
return irBuilder.irBlock {
|
||||||
val constructorCall = irCall(topLevelSuiteConstructor).apply {
|
val constructorCall = irCall(topLevelSuiteConstructor).apply {
|
||||||
putValueArgument(0, irString(suiteName))
|
putValueArgument(0, irString(topLevelSuiteName))
|
||||||
}
|
}
|
||||||
val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite")
|
val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite")
|
||||||
generateFunctionRegistration(testSuiteVal,
|
generateFunctionRegistration(testSuiteVal,
|
||||||
@@ -591,14 +590,17 @@ internal class TestProcessor (val context: Context) {
|
|||||||
|
|
||||||
private fun createTestSuites(irFile: IrFile, annotationCollector: AnnotationCollector) {
|
private fun createTestSuites(irFile: IrFile, annotationCollector: AnnotationCollector) {
|
||||||
val statements = mutableListOf<IrExpression>()
|
val statements = mutableListOf<IrExpression>()
|
||||||
|
|
||||||
annotationCollector.testClasses.filter {
|
annotationCollector.testClasses.filter {
|
||||||
it.value.functions.any { it.kind == FunctionKind.TEST }
|
it.value.functions.any { it.kind == FunctionKind.TEST }
|
||||||
}.forEach { _, testClass ->
|
}.forEach { (_, testClass) ->
|
||||||
statements.add(generateClassSuite(irFile, testClass))
|
statements.add(generateClassSuite(irFile, testClass))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (annotationCollector.topLevelFunctions.isNotEmpty()) {
|
if (annotationCollector.topLevelFunctions.isNotEmpty()) {
|
||||||
generateTopLevelSuite(irFile, annotationCollector.topLevelFunctions)?.let { statements.add(it) }
|
generateTopLevelSuite(irFile, annotationCollector.topLevelSuiteName, annotationCollector.topLevelFunctions)?.let { statements.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statements.isNotEmpty()) {
|
if (statements.isNotEmpty()) {
|
||||||
context.irFactory.buildFun {
|
context.irFactory.buildFun {
|
||||||
startOffset = SYNTHETIC_OFFSET
|
startOffset = SYNTHETIC_OFFSET
|
||||||
@@ -618,6 +620,25 @@ internal class TestProcessor (val context: Context) {
|
|||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region test functions to be dumped
|
||||||
|
private fun recordTestFunctions(annotationCollector: AnnotationCollector) {
|
||||||
|
if (context.config.testDumpFile == null) return
|
||||||
|
|
||||||
|
fun recordFunction(suiteClassId: ClassId, function: TestFunction) {
|
||||||
|
if (function.kind == FunctionKind.TEST)
|
||||||
|
context.testCasesToDump.computeIfAbsent(suiteClassId) { mutableListOf() } += function.functionName
|
||||||
|
}
|
||||||
|
|
||||||
|
annotationCollector.topLevelFunctions.forEach { function ->
|
||||||
|
recordFunction(annotationCollector.topLevelSuiteClassId, function)
|
||||||
|
}
|
||||||
|
|
||||||
|
annotationCollector.testClasses.values.forEach { testClass ->
|
||||||
|
testClass.functions.forEach { function -> recordFunction(testClass.suiteClassId, function) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
private fun shouldProcessFile(irFile: IrFile): Boolean = irFile.packageFragmentDescriptor.module.let {
|
private fun shouldProcessFile(irFile: IrFile): Boolean = irFile.packageFragmentDescriptor.module.let {
|
||||||
// Process test annotations in source libraries too.
|
// Process test annotations in source libraries too.
|
||||||
it == context.moduleDescriptor || it in context.getIncludedLibraryDescriptors()
|
it == context.moduleDescriptor || it in context.getIncludedLibraryDescriptors()
|
||||||
@@ -632,5 +653,6 @@ internal class TestProcessor (val context: Context) {
|
|||||||
val annotationCollector = AnnotationCollector(irFile)
|
val annotationCollector = AnnotationCollector(irFile)
|
||||||
irFile.acceptChildrenVoid(annotationCollector)
|
irFile.acceptChildrenVoid(annotationCollector)
|
||||||
createTestSuites(irFile, annotationCollector)
|
createTestSuites(irFile, annotationCollector)
|
||||||
|
recordTestFunctions(annotationCollector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user