[debugger] Fixed NPE in Coroutines View

IDEA-374561


(cherry picked from commit 37474b08ca8a3c0751b36fa883756c1dbf8b94dc)

IJ-CR-167001

GitOrigin-RevId: 5b92085c4b025cd28b0c572ea79648b493c19cbc
This commit is contained in:
Maria Sokolova
2025-06-23 16:56:37 +02:00
committed by intellij-monorepo-bot
parent f5b575c1b9
commit 03000b963a
18 changed files with 458 additions and 40 deletions

View File

@@ -177,7 +177,8 @@ public final class CoroutinesDebugHelper {
for (int i = 0; i < coroutineInfos.length; i++) {
lastObservedStackTraces[i] = lastObservedStackTrace(coroutineInfos[i]);
}
dump[3] = lastObservedStackTraces;
dump = Arrays.copyOf(dump, dump.length + 1);
dump[4] = lastObservedStackTraces;
return dump;
} catch (Throwable e) {
return null;

View File

@@ -7,6 +7,7 @@ import com.intellij.debugger.impl.DebuggerUtilsImpl.logError
import com.intellij.rt.debugger.coroutines.CoroutinesDebugHelper
import com.sun.jdi.ArrayReference
import com.sun.jdi.StringReference
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.idea.debugger.base.util.evaluate.DefaultExecutionContext
import org.jetbrains.kotlin.idea.debugger.coroutine.callMethodFromHelper
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoCache
@@ -51,7 +52,8 @@ class CoroutineDebugProbesProxy(val suspendContext: SuspendContextImpl) {
*
* The corresponding properties [CoroutineInfoData.job] and [CoroutineInfoData.parentJob] are set to the obtained values.
*/
internal fun fetchAndSetJobsAndParentsForCoroutines(infos: List<CoroutineInfoData>): Boolean {
@ApiStatus.Internal
fun fetchAndSetJobsAndParentsForCoroutines(infos: List<CoroutineInfoData>): Boolean {
val executionContext = suspendContext.executionContext() ?: return false
val debugCoroutineInfos = infos.map { it.debugCoroutineInfoRef }
val array = callMethodFromHelper(CoroutinesDebugHelper::class.java, executionContext, "getJobsAndParentsForCoroutines", debugCoroutineInfos)

View File

@@ -40,13 +40,13 @@ internal class CoroutinesInfoFromJsonAndReferencesProvider(
}
val coroutinesInfoAsJsonString = arrayValues[0].safeAs<StringReference>()?.value()
?: error("The first element of the result array must be a string")
?: error("The 1st element of the result array must be a string")
val lastObservedThreadRefs = arrayValues[1].safeAs<ArrayReference>()?.toTypedList<ThreadReference?>()
?: error("The second element of the result array must be an array")
?: error("The 2nd element of the result array must be an array")
val lastObservedFrameRefs = arrayValues[2].safeAs<ArrayReference>()?.toTypedList<ObjectReference?>()
?: error("The third element of the result array must be an array")
?: error("The 3rd element of the result array must be an array")
val coroutineInfoRefs = arrayValues[3].safeAs<ArrayReference>()?.toTypedList<ObjectReference>()
?: error("The fourth element of the result array must be an array")
?: error("The 4th element of the result array must be an array")
val coroutinesInfo = Gson().fromJson(coroutinesInfoAsJsonString, Array<CoroutineInfoFromJson>::class.java)
if (coroutineInfoRefs.size != lastObservedFrameRefs.size ||
@@ -55,7 +55,7 @@ internal class CoroutinesInfoFromJsonAndReferencesProvider(
error("Arrays must have equal sizes")
}
return calculateCoroutineInfoData(coroutinesInfo, coroutineInfoRefs, lastObservedThreadRefs, lastObservedFrameRefs)
return calculateCoroutineInfoData(coroutinesInfo, coroutineInfoRefs, lastObservedThreadRefs, lastObservedFrameRefs, null)
}
fun dumpCoroutinesWithStacktraces(): List<CoroutineInfoData>? {
@@ -63,18 +63,20 @@ internal class CoroutinesInfoFromJsonAndReferencesProvider(
val arrayValues = (array as? ArrayReference)?.values ?: return null
if (arrayValues.size != 4) {
error("The result array of 'dumpCoroutinesWithStacktracesAsJson' should be of size 4")
if (arrayValues.size != 5) {
error("The result array of 'dumpCoroutinesWithStacktracesAsJson' should be of size 5")
}
val coroutinesInfoAsJsonString = arrayValues[0].safeAs<StringReference>()?.value()
?: error("The first element of the result array must be a string")
?: error("The 1st element of the result array must be a string")
val lastObservedThreadRefs = arrayValues[1].safeAs<ArrayReference>()?.toTypedList<ThreadReference?>()
?: error("The second element of the result array must be an array")
?: error("The 2nd element of the result array must be an array")
val lastObservedFrameRefs = arrayValues[2].safeAs<ArrayReference>()?.toTypedList<ObjectReference?>()
?: error("The third element of the result array must be an array")
val lastObservedStackTraceJsons = arrayValues[3].safeAs<ArrayReference>()?.toTypedList<StringReference>()
?: error("The fourth element of the result array must be an array")
?: error("The 3rd element of the result array must be an array")
val coroutineInfoRefs = arrayValues[3].safeAs<ArrayReference>()?.toTypedList<ObjectReference>()
?: error("The 4th element of the result array must be an array")
val lastObservedStackTraceJsons = arrayValues[4].safeAs<ArrayReference>()?.toTypedList<StringReference>()
?: error("The 5th element of the result array must be an array")
val coroutinesInfo = Gson().fromJson(coroutinesInfoAsJsonString, Array<CoroutineInfoFromJson>::class.java)
val lastObservedStackTraces: List<List<Location>> = lastObservedStackTraceJsons.map {
@@ -85,11 +87,12 @@ internal class CoroutinesInfoFromJsonAndReferencesProvider(
if (lastObservedStackTraces.size != lastObservedFrameRefs.size ||
lastObservedFrameRefs.size != coroutinesInfo.size ||
coroutineInfoRefs.size != coroutinesInfo.size ||
coroutinesInfo.size != lastObservedThreadRefs.size) {
error("Arrays must have equal sizes")
}
return calculateCoroutineInfoDataWithStacktraces(coroutinesInfo, lastObservedThreadRefs, lastObservedFrameRefs, lastObservedStackTraces)
return calculateCoroutineInfoData(coroutinesInfo, coroutineInfoRefs, lastObservedThreadRefs, lastObservedFrameRefs, lastObservedStackTraces)
}
private fun fallbackToOldMirrorDump(executionContext: DefaultExecutionContext): ArrayReference? {
@@ -103,7 +106,8 @@ internal class CoroutinesInfoFromJsonAndReferencesProvider(
coroutineInfos: Array<CoroutineInfoFromJson>,
coroutineInfoRefs: List<ObjectReference>,
lastObservedThreadRefs: List<ThreadReference?>,
lastObservedFrameRefs: List<ObjectReference?>
lastObservedFrameRefs: List<ObjectReference?>,
lastObservedStackTraces: List<List<Location>>?
): List<CoroutineInfoData> {
return coroutineInfoRefs.mapIndexed { i, ref ->
val info = coroutineInfos[i]
@@ -115,28 +119,8 @@ internal class CoroutinesInfoFromJsonAndReferencesProvider(
lastObservedFrame = lastObservedFrameRefs[i],
lastObservedThread = lastObservedThreadRefs[i],
debugCoroutineInfoRef = ref,
stackFrameProvider = stackFramesProvider
)
}
}
private fun calculateCoroutineInfoDataWithStacktraces(
coroutineInfos: Array<CoroutineInfoFromJson>,
lastObservedThreadRefs: List<ThreadReference?>,
lastObservedFrameRefs: List<ObjectReference?>,
lastObservedStackTraces: List<List<Location>>
): List<CoroutineInfoData> {
return coroutineInfos.mapIndexed { i, info ->
CoroutineInfoData(
name = info.name,
id = info.sequenceNumber,
state = info.state,
dispatcher = info.dispatcher,
lastObservedFrame = lastObservedFrameRefs[i],
lastObservedThread = lastObservedThreadRefs[i],
debugCoroutineInfoRef = null,
stackFrameProvider = null,
lastObservedStackTrace = lastObservedStackTraces[i]
stackFrameProvider = stackFramesProvider,
lastObservedStackTrace = lastObservedStackTraces?.get(i) ?: emptyList()
)
}
}

View File

@@ -0,0 +1,24 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.k2.debugger.test.cases
import org.jetbrains.kotlin.config.JvmClosureGenerationScheme
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.idea.debugger.test.*
import org.jetbrains.kotlin.idea.k2.debugger.test.K2DebuggerTestCompilerFacility
abstract class AbstractK2IdeK1CoroutineViewJobHierarchyTest : AbstractCoroutineViewJobHierarchyTest() {
override fun createDebuggerTestCompilerFacility(
testFiles: TestFiles,
jvmTarget: JvmTarget,
compileConfig: TestCompileConfiguration
): DebuggerTestCompilerFacility {
return K2DebuggerTestCompilerFacility(project, testFiles, jvmTarget, compileConfig)
}
}
abstract class AbstractK2IdeK2CoroutineViewJobHierarchyTest : AbstractK2IdeK1CoroutineViewJobHierarchyTest() {
override val compileWithK2 = true
override fun lambdasGenerationScheme() = JvmClosureGenerationScheme.INDY
}

View File

@@ -0,0 +1,47 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.k2.debugger.test.cases;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode;
import org.jetbrains.kotlin.idea.base.test.TestRoot;
import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.idea.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
/**
* This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}.
* DO NOT MODIFY MANUALLY.
*/
@SuppressWarnings("all")
@TestRoot("jvm-debugger/test/k2")
@TestDataPath("$CONTENT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/coroutinesView")
public class K2IdeK1CoroutineViewJobHierarchyTestGenerated extends AbstractK2IdeK1CoroutineViewJobHierarchyTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("coroutinesHierarchy2.kt")
public void testCoroutinesHierarchy2() throws Exception {
runTest("../testData/coroutinesView/coroutinesHierarchy2.kt");
}
@TestMetadata("coroutinesHierarchy3.kt")
public void testCoroutinesHierarchy3() throws Exception {
runTest("../testData/coroutinesView/coroutinesHierarchy3.kt");
}
@TestMetadata("oneCoroutine.kt")
public void testOneCoroutine() throws Exception {
runTest("../testData/coroutinesView/oneCoroutine.kt");
}
}

View File

@@ -0,0 +1,47 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.k2.debugger.test.cases;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode;
import org.jetbrains.kotlin.idea.base.test.TestRoot;
import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.idea.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
/**
* This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}.
* DO NOT MODIFY MANUALLY.
*/
@SuppressWarnings("all")
@TestRoot("jvm-debugger/test/k2")
@TestDataPath("$CONTENT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/coroutinesView")
public class K2IdeK2CoroutineViewJobHierarchyTestGenerated extends AbstractK2IdeK2CoroutineViewJobHierarchyTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("coroutinesHierarchy2.kt")
public void testCoroutinesHierarchy2() throws Exception {
runTest("../testData/coroutinesView/coroutinesHierarchy2.kt");
}
@TestMetadata("coroutinesHierarchy3.kt")
public void testCoroutinesHierarchy3() throws Exception {
runTest("../testData/coroutinesView/coroutinesHierarchy3.kt");
}
@TestMetadata("oneCoroutine.kt")
public void testOneCoroutine() throws Exception {
runTest("../testData/coroutinesView/oneCoroutine.kt");
}
}

View File

@@ -0,0 +1,71 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.debugger.test
import com.intellij.debugger.engine.executeOnDMT
import com.intellij.debugger.impl.PrioritizedTask
import org.jetbrains.kotlin.config.JvmClosureGenerationScheme
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineInfoData
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.CoroutineDebugProbesProxy
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
abstract class AbstractCoroutineViewJobHierarchyTest : KotlinDescriptorTestCaseWithStackFrames() {
override fun doMultiFileTest(files: TestFiles, preferences: DebuggerPreferences) {
doOnBreakpoint {
val suspendContext = this
try {
executeOnDMT(suspendContext, PrioritizedTask.Priority.NORMAL) {
val coroutineDebugProxy = CoroutineDebugProbesProxy(suspendContext)
val coroutineCache = coroutineDebugProxy.dumpCoroutines()
if (coroutineCache.isOk()) {
val cache = coroutineCache.cache
val isHierarchyBuilt = coroutineDebugProxy.fetchAndSetJobsAndParentsForCoroutines(cache)
if (isHierarchyBuilt) {
printCoroutinesJobHierarchy(cache)
} else {
printCoroutineInfos(cache)
}
}
}
} finally {
resume(suspendContext)
}
}
}
private fun printCoroutineInfos(infos: List<CoroutineInfoData>) {
for (info in infos) {
out(0, info.name + " " + info.state)
}
}
private fun printCoroutinesJobHierarchy(infos: List<CoroutineInfoData>) {
val parentJobToChildCoroutineInfos = infos.groupBy { it.parentJob }
val jobToCoroutineInfo = infos.associateBy { it.job }
val rootJobs = infos.filter { it.parentJob == null }.mapNotNull { it.job }
out(0, "==== Hierarchy of coroutines =====")
for (root in rootJobs) {
val rootCoroutineInfo = jobToCoroutineInfo[root]
if (rootCoroutineInfo == null) {
out(0, root)
} else {
printInfo(rootCoroutineInfo, parentJobToChildCoroutineInfos, 0)
}
}
}
private fun printInfo(info: CoroutineInfoData, jobToChildCoroutineInfos: Map<String?, List<CoroutineInfoData>>, indent: Int) {
out(indent, info.name + " " + info.state)
val children = jobToChildCoroutineInfos[info.job] ?: emptyList()
for (child in children) {
printInfo(child, jobToChildCoroutineInfos, indent + 1)
}
}
}
abstract class AbstractK1IdeK2CoroutineViewTest : AbstractCoroutineViewJobHierarchyTest() {
override val compileWithK2 = true
override fun lambdasGenerationScheme() = JvmClosureGenerationScheme.INDY
}

View File

@@ -0,0 +1,47 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode;
import org.jetbrains.kotlin.idea.base.test.TestRoot;
import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.idea.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
/**
* This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}.
* DO NOT MODIFY MANUALLY.
*/
@SuppressWarnings("all")
@TestRoot("jvm-debugger/test")
@TestDataPath("$CONTENT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("testData/coroutinesView")
public class CoroutineViewJobHierarchyTestGenerated extends AbstractCoroutineViewJobHierarchyTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K1;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("coroutinesHierarchy2.kt")
public void testCoroutinesHierarchy2() throws Exception {
runTest("testData/coroutinesView/coroutinesHierarchy2.kt");
}
@TestMetadata("coroutinesHierarchy3.kt")
public void testCoroutinesHierarchy3() throws Exception {
runTest("testData/coroutinesView/coroutinesHierarchy3.kt");
}
@TestMetadata("oneCoroutine.kt")
public void testOneCoroutine() throws Exception {
runTest("testData/coroutinesView/oneCoroutine.kt");
}
}

View File

@@ -0,0 +1,47 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.debugger.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode;
import org.jetbrains.kotlin.idea.base.test.TestRoot;
import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.idea.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
/**
* This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}.
* DO NOT MODIFY MANUALLY.
*/
@SuppressWarnings("all")
@TestRoot("jvm-debugger/test")
@TestDataPath("$CONTENT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("testData/coroutinesView")
public class K1IdeK2CoroutineViewTestGenerated extends AbstractK1IdeK2CoroutineViewTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K1;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("coroutinesHierarchy2.kt")
public void testCoroutinesHierarchy2() throws Exception {
runTest("testData/coroutinesView/coroutinesHierarchy2.kt");
}
@TestMetadata("coroutinesHierarchy3.kt")
public void testCoroutinesHierarchy3() throws Exception {
runTest("testData/coroutinesView/coroutinesHierarchy3.kt");
}
@TestMetadata("oneCoroutine.kt")
public void testOneCoroutine() throws Exception {
runTest("testData/coroutinesView/oneCoroutine.kt");
}
}

View File

@@ -29,11 +29,11 @@ abstract class KotlinDescriptorTestCaseWithStackFrames : KotlinDescriptorTestCas
out(INDENT_VARIABLES, "(${variables.joinToString()})")
}
private fun out(text: String) {
protected fun out(text: String) {
println(text, ProcessOutputTypes.SYSTEM)
}
private fun out(indent: Int, text: String) {
protected fun out(indent: Int, text: String) {
println("\t".repeat(indent) + text, ProcessOutputTypes.SYSTEM)
}

View File

@@ -0,0 +1,14 @@
package coroutinesView
// ATTACH_LIBRARY: maven(org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2)-javaagent
import kotlinx.coroutines.*
fun main() {
runBlocking(CoroutineName("root")) {
println()
//Breakpoint!
delay(11L)
println()
}
}

View File

@@ -0,0 +1,9 @@
LineBreakpoint created at coroutinesHierarchy2.kt:11
Run Java
Connected to the target VM
coroutinesHierarchy2.kt:11
==== Hierarchy of coroutines =====
root RUNNING
Disconnected from the target VM
Process finished with exit code 0

View File

@@ -0,0 +1,57 @@
package coroutinesView
// ATTACH_LIBRARY: maven(org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2)-javaagent
import kotlinx.coroutines.*
fun main() {
runBlocking(CoroutineName("root")) {
test()
}
}
suspend fun test() {
coroutineScope {
launch(CoroutineName("launch1")) {
delay(1)
println()
delay(1)
}
launch(CoroutineName("launch2")) {
coroutineScope {
val a = async(CoroutineName("childAsync1")) {
val coroutineVar = 1
delay(100)
println("coroutineVar=$coroutineVar")
6
}
val b = async(CoroutineName("childAsync2")) {
val coroutineVar = 2
delay(100)
println("coroutineVar=$coroutineVar")
7
}
}
}
withContext(Dispatchers.Default) {
coroutineScope {
val a = async(CoroutineName("async1")) {
val coroutineVar = 1
delay(100)
println("coroutineVar=$coroutineVar") // ← breakpoint
6
}
val b = async(CoroutineName("async2")) {
val coroutineVar = 2
delay(100)
println("coroutineVar=$coroutineVar")
7
}
//Breakpoint!
println("result: ${a.await() * b.await()}")
}
}
}
}

View File

@@ -0,0 +1,14 @@
LineBreakpoint created at coroutinesHierarchy3.kt:53
Run Java
Connected to the target VM
coroutinesHierarchy3.kt:53
==== Hierarchy of coroutines =====
root RUNNING
launch2 SUSPENDED
childAsync1 SUSPENDED
childAsync2 SUSPENDED
async1 SUSPENDED
async2 SUSPENDED
Disconnected from the target VM
Process finished with exit code 0

View File

@@ -0,0 +1,30 @@
package coroutinesView
// ATTACH_LIBRARY: maven(org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2)-javaagent
import kotlinx.coroutines.*
fun main() {
runBlocking(CoroutineName("root")) {
a()
}
}
suspend fun a() {
val a = "a"
b(a)
val aLate = a
}
suspend fun b(paramA: String) {
yield()
val b = "b"
c(b)
val dead = paramA
}
suspend fun c(paramB: String) {
val c = "c"
//Breakpoint!
val dead = paramB
}

View File

@@ -0,0 +1,9 @@
LineBreakpoint created at oneCoroutine.kt:29
Run Java
Connected to the target VM
oneCoroutine.kt:29
==== Hierarchy of coroutines =====
root RUNNING
Disconnected from the target VM
Process finished with exit code 0

View File

@@ -299,6 +299,12 @@ private fun assembleWorkspace(): TWorkspace = workspace(KotlinPluginMode.K1) {
}
}
listOf(AbstractCoroutineViewJobHierarchyTest::class, AbstractK1IdeK2CoroutineViewTest::class).forEach {
testClass(it) {
model("coroutinesView")
}
}
testClass<AbstractIrSequenceTraceTestCase> { // TODO: implement mapping logic for terminal operations
model("sequence/streams/sequence", excludedDirectories = listOf("terminal"))
}

View File

@@ -98,6 +98,15 @@ internal fun MutableTWorkspace.generateK2DebuggerTests() {
}
}
listOf(
AbstractK2IdeK2CoroutineViewJobHierarchyTest::class,
AbstractK2IdeK1CoroutineViewJobHierarchyTest::class,
).forEach {
testClass(it) {
model("coroutinesView")
}
}
//testClass<AbstractSequenceTraceTestCase> { // TODO: implement mapping logic for terminal operations
// model("sequence/streams/sequence", excludedDirectories = listOf("terminal"))
//}