• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.coroutines.test
6 
7 import kotlinx.coroutines.*
8 import kotlin.coroutines.*
9 import kotlin.jvm.*
10 import kotlin.time.*
11 
12 /**
13  * A test dispatcher that can interface with a [TestCoroutineScheduler].
14  *
15  * The available implementations are:
16  * * [StandardTestDispatcher] is a dispatcher that places new tasks into a queue.
17  * * [UnconfinedTestDispatcher] is a dispatcher that behaves like [Dispatchers.Unconfined] while allowing to control
18  *   the virtual time.
19  */
20 @Suppress("INVISIBLE_REFERENCE")
21 public abstract class TestDispatcher internal constructor() : CoroutineDispatcher(), Delay, DelayWithTimeoutDiagnostics {
22     /** The scheduler that this dispatcher is linked to. */
23     public abstract val scheduler: TestCoroutineScheduler
24 
25     /** Notifies the dispatcher that it should process a single event marked with [marker] happening at time [time]. */
processEventnull26     internal fun processEvent(marker: Any) {
27         check(marker is Runnable)
28         marker.run()
29     }
30 
31     /** @suppress */
scheduleResumeAfterDelaynull32     override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
33         val timedRunnable = CancellableContinuationRunnable(continuation, this)
34         val handle = scheduler.registerEvent(
35             this,
36             timeMillis,
37             timedRunnable,
38             continuation.context,
39             ::cancellableRunnableIsCancelled
40         )
41         continuation.disposeOnCancellation(handle)
42     }
43 
44     /** @suppress */
invokeOnTimeoutnull45     override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle =
46         scheduler.registerEvent(this, timeMillis, block, context) { false }
47 
48     /** @suppress */
49     @Suppress("CANNOT_OVERRIDE_INVISIBLE_MEMBER")
50     @Deprecated("Is only needed internally", level = DeprecationLevel.HIDDEN)
timeoutMessagenull51     public override fun timeoutMessage(timeout: Duration): String =
52         "Timed out after $timeout of _virtual_ (kotlinx.coroutines.test) time. " +
53             "To use the real time, wrap 'withTimeout' in 'withContext(Dispatchers.Default.limitedParallelism(1))'"
54 }
55 
56 /**
57  * This class exists to allow cleanup code to avoid throwing for cancelled continuations scheduled
58  * in the future.
59  */
60 private class CancellableContinuationRunnable(
61     @JvmField val continuation: CancellableContinuation<Unit>,
62     private val dispatcher: CoroutineDispatcher
63 ) : Runnable {
64     override fun run() = with(dispatcher) { with(continuation) { resumeUndispatched(Unit) } }
65 }
66 
cancellableRunnableIsCancellednull67 private fun cancellableRunnableIsCancelled(runnable: CancellableContinuationRunnable): Boolean =
68     !runnable.continuation.isActive
69