Skip to content

Dispatchers.Main.isMissing throws when dispatcher is missing (since 1.10.0) #4325

@consp1racy

Description

@consp1racy

Describe the bug

Expected behavior: Dispatchers.Main.isMissing() returns true in JVM tests where Dispatchers.setMain() wasn't called.

Actual behavior:

java.lang.IllegalStateException: Dispatchers.Main was accessed when the platform dispatcher was absent and the test dispatcher was unset. Please make sure that Dispatchers.setMain() is called before accessing Dispatchers.Main and that Dispatchers.Main is not accessed after Dispatchers.resetMain().
	at kotlinx.coroutines.test.internal.TestMainDispatcherJvmKt.reportMissingMainCoroutineDispatcher(TestMainDispatcherJvm.kt:45)
	at kotlinx.coroutines.test.internal.TestMainDispatcherJvmKt.access$reportMissingMainCoroutineDispatcher(TestMainDispatcherJvm.kt:1)
	at kotlinx.coroutines.test.internal.TestMainDispatcherFactory.createDispatcher$lambda$4(TestMainDispatcherJvm.kt:20)
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:83)
	at kotlinx.coroutines.test.internal.TestMainDispatcher.getMainDispatcher(TestMainDispatcher.kt:18)
	at kotlinx.coroutines.test.internal.TestMainDispatcher.getDispatcher(TestMainDispatcher.kt:22)
	at kotlinx.coroutines.test.internal.TestMainDispatcher.getImmediate(TestMainDispatcher.kt:28)
	at kotlinx.coroutines.internal.MainDispatchersKt.isMissing(MainDispatchers.kt:62)
	...

Probably introduced here.

Provide a Reproducer

The following method didn't crash before when called in JVM tests where Dispatchers.setMain() wasn't called:

/**
 * @throws AssertionError when called from the main thread and assertions are enabled
 */
@WorkerThread
fun <T> runBlockingOrThrow(
    context: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T,
): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }

    val mainDispatcher = Dispatchers.Main.immediate
    if (!mainDispatcher.isMissing()) {
        assert(mainDispatcher.isDispatchNeeded(context)) {
            "runBlockingOrThrow MUST NOT be called from the main thread"
        }
    }

    return runBlocking(context, block)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions