1 /* 2 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.coroutines.test.internal 6 7 import kotlinx.coroutines.* 8 import kotlinx.coroutines.internal.* 9 import kotlin.coroutines.* 10 11 /** 12 * The testable main dispatcher used by kotlinx-coroutines-test. 13 * It is a [MainCoroutineDispatcher] which delegates all actions to a settable delegate. 14 */ 15 internal class TestMainDispatcher(private val mainFactory: MainDispatcherFactory) : MainCoroutineDispatcher(), Delay { 16 private var _delegate: CoroutineDispatcher? = null 17 private val delegate: CoroutineDispatcher get() { <lambda>null18 _delegate?.let { return it } <lambda>null19 mainFactory.tryCreateDispatcher(emptyList()).let { 20 // If we've failed to create a dispatcher, do no set _delegate 21 if (!isMissing()) { 22 _delegate = it 23 } 24 return it 25 } 26 } 27 28 @Suppress("INVISIBLE_MEMBER") 29 private val delay: Delay get() = delegate as? Delay ?: DefaultDelay 30 31 override val immediate: MainCoroutineDispatcher 32 get() = (delegate as? MainCoroutineDispatcher)?.immediate ?: this 33 dispatchnull34 override fun dispatch(context: CoroutineContext, block: Runnable) { 35 delegate.dispatch(context, block) 36 } 37 38 @ExperimentalCoroutinesApi isDispatchNeedednull39 override fun isDispatchNeeded(context: CoroutineContext): Boolean = delegate.isDispatchNeeded(context) 40 41 override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) { 42 delay.scheduleResumeAfterDelay(timeMillis, continuation) 43 } 44 delaynull45 override suspend fun delay(time: Long) { 46 delay.delay(time) 47 } 48 invokeOnTimeoutnull49 override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle { 50 return delay.invokeOnTimeout(timeMillis, block) 51 } 52 setDispatchernull53 public fun setDispatcher(dispatcher: CoroutineDispatcher) { 54 _delegate = dispatcher 55 } 56 resetDispatchernull57 public fun resetDispatcher() { 58 _delegate = null 59 } 60 } 61 62 internal class TestMainDispatcherFactory : MainDispatcherFactory { 63 createDispatchernull64 override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher { 65 val originalFactory = allFactories.asSequence() 66 .filter { it !== this } 67 .maxBy { it.loadPriority } ?: MissingMainCoroutineDispatcherFactory 68 return TestMainDispatcher(originalFactory) 69 } 70 71 /** 72 * [Int.MAX_VALUE] -- test dispatcher always wins no matter what factories are present in the classpath. 73 * By default all actions are delegated to the second-priority dispatcher, so that it won't be the issue. 74 */ 75 override val loadPriority: Int 76 get() = Int.MAX_VALUE 77 } 78