| /* |
| * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
| */ |
| |
| package kotlinx.coroutines.test |
| |
| import kotlinx.coroutines.* |
| import kotlin.coroutines.* |
| |
| /** |
| * [CoroutineDispatcher] that performs both immediate and lazy execution of coroutines in tests |
| * and uses a [TestCoroutineScheduler] to control its virtual clock. |
| * |
| * By default, [TestCoroutineDispatcher] is immediate. That means any tasks scheduled to be run without delay are |
| * immediately executed. If they were scheduled with a delay, the virtual clock-time must be advanced via one of the |
| * methods on the dispatcher's [scheduler]. |
| * |
| * When switched to lazy execution using [pauseDispatcher] any coroutines started via [launch] or [async] will |
| * not execute until a call to [DelayController.runCurrent] or the virtual clock-time has been advanced via one of the |
| * methods on [DelayController]. |
| * |
| * @see DelayController |
| */ |
| @Deprecated("The execution order of `TestCoroutineDispatcher` can be confusing, and the mechanism of " + |
| "pausing is typically misunderstood. Please use `StandardTestDispatcher` or `UnconfinedTestDispatcher` instead.", |
| level = DeprecationLevel.WARNING) |
| // Since 1.6.0, ERROR in 1.7.0 and removed as experimental in 1.8.0 |
| public class TestCoroutineDispatcher(public override val scheduler: TestCoroutineScheduler = TestCoroutineScheduler()): |
| TestDispatcher(), Delay, SchedulerAsDelayController |
| { |
| private var dispatchImmediately = true |
| set(value) { |
| field = value |
| if (value) { |
| // there may already be tasks from setup code we need to run |
| scheduler.advanceUntilIdle() |
| } |
| } |
| |
| /** @suppress */ |
| override fun dispatch(context: CoroutineContext, block: Runnable) { |
| checkSchedulerInContext(scheduler, context) |
| if (dispatchImmediately) { |
| scheduler.sendDispatchEvent(context) |
| block.run() |
| } else { |
| post(block, context) |
| } |
| } |
| |
| /** @suppress */ |
| override fun dispatchYield(context: CoroutineContext, block: Runnable) { |
| checkSchedulerInContext(scheduler, context) |
| post(block, context) |
| } |
| |
| /** @suppress */ |
| override fun toString(): String = "TestCoroutineDispatcher[scheduler=$scheduler]" |
| |
| private fun post(block: Runnable, context: CoroutineContext) = |
| scheduler.registerEvent(this, 0, block, context) { false } |
| |
| /** @suppress */ |
| override suspend fun pauseDispatcher(block: suspend () -> Unit) { |
| val previous = dispatchImmediately |
| dispatchImmediately = false |
| try { |
| block() |
| } finally { |
| dispatchImmediately = previous |
| } |
| } |
| |
| /** @suppress */ |
| override fun pauseDispatcher() { |
| dispatchImmediately = false |
| } |
| |
| /** @suppress */ |
| override fun resumeDispatcher() { |
| dispatchImmediately = true |
| } |
| } |