@@ -13,9 +13,9 @@ import kotlin.jvm.*
13
13
/* *
14
14
* This is a scheduler for coroutines used in tests, providing the delay-skipping behavior.
15
15
*
16
- * [Test dispatchers][TestCoroutineDispatcher ] are parameterized with a scheduler. Several dispatchers can share the
17
- * same scheduler, in which case * their knowledge about the virtual time will be synchronized. When the dispatchers
18
- * require scheduling an event at a * later point in time, they notify the scheduler, which will establish the order of
16
+ * [Test dispatchers][TestDispatcher ] are parameterized with a scheduler. Several dispatchers can share the
17
+ * same scheduler, in which case their knowledge about the virtual time will be synchronized. When the dispatchers
18
+ * require scheduling an event at a later point in time, they notify the scheduler, which will establish the order of
19
19
* the tasks.
20
20
*
21
21
* The scheduler can be queried to advance the time (via [advanceTimeBy]), run all the scheduled tasks advancing the
@@ -26,6 +26,7 @@ import kotlin.jvm.*
26
26
// TODO: maybe make this a `TimeSource`?
27
27
public class TestCoroutineScheduler : AbstractCoroutineContextElement (TestCoroutineScheduler ), CoroutineContext.Element {
28
28
29
+ /* * @suppress */
29
30
public companion object Key: CoroutineContext.Key<TestCoroutineScheduler>
30
31
31
32
/* * This heap stores the knowledge about which dispatchers are interested in which moments of virtual time. */
@@ -45,8 +46,8 @@ public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCorouti
45
46
private set
46
47
47
48
/* *
48
- * Registers a request for the scheduler to notify [dispatcher] at a virtual moment [timeDeltaMillis] milliseconds later
49
- * via [TestDispatcher.processEvent], which will be called with the provided [marker] object.
49
+ * Registers a request for the scheduler to notify [dispatcher] at a virtual moment [timeDeltaMillis] milliseconds
50
+ * later via [TestDispatcher.processEvent], which will be called with the provided [marker] object.
50
51
*
51
52
* Returns the handler which can be used to cancel the registration.
52
53
*/
@@ -74,7 +75,7 @@ public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCorouti
74
75
* Runs the enqueued tasks in the specified order, advancing the virtual time as needed until there are no more
75
76
* tasks associated with the dispatchers linked to this scheduler.
76
77
*
77
- * A breaking change from [TestCoroutineDispatcher.advanceTimeBy] is that it no longer returns the total amount of
78
+ * A breaking change from [TestCoroutineDispatcher.advanceTimeBy] is that it no longer returns the total number of
78
79
* milliseconds by which the execution of this method has advanced the virtual time. If you want to recreate that
79
80
* functionality, query [currentTime] before and after the execution to achieve the same result.
80
81
*/
@@ -124,24 +125,22 @@ public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCorouti
124
125
*/
125
126
@ExperimentalCoroutinesApi
126
127
public fun advanceTimeBy (delayTimeMillis : Long ) {
127
- require(delayTimeMillis >= 0 ) { " " }
128
+ require(delayTimeMillis >= 0 ) { " Can not advance time by a negative delay: $delayTimeMillis " }
128
129
val startingTime = currentTime
129
130
val targetTime = addClamping(startingTime, delayTimeMillis)
130
131
while (true ) {
131
132
val event = synchronized(lock) {
132
133
val timeMark = currentTime
133
- val event = events.peek()
134
+ val event = events.removeFirstIf { targetTime > it.time }
134
135
when {
135
- event == null || targetTime <= event.time -> {
136
+ event == null -> {
136
137
currentTime = targetTime
137
138
return
138
139
}
139
140
timeMark > event.time -> currentTimeAheadOfEvents()
140
141
else -> {
141
- val event2 = events.removeFirstOrNull()
142
- if (event != = event2) concurrentModificationUnderLock()
143
142
currentTime = event.time
144
- event2
143
+ event
145
144
}
146
145
}
147
146
}
@@ -166,7 +165,6 @@ public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCorouti
166
165
167
166
// Some error-throwing functions for pretty stack traces
168
167
private fun currentTimeAheadOfEvents (): Nothing = invalidSchedulerState()
169
- private fun concurrentModificationUnderLock (): Nothing = invalidSchedulerState()
170
168
171
169
private fun invalidSchedulerState (): Nothing =
172
170
throw IllegalStateException (" The test scheduler entered an invalid state. Please report this at https://github.com/Kotlin/kotlinx.coroutines/issues." )
@@ -177,16 +175,13 @@ private class TestDispatchEvent<T>(
177
175
private val count : Long ,
178
176
@JvmField val time : Long ,
179
177
@JvmField val marker : T ,
180
- val isCancelled : () -> Boolean
178
+ @JvmField val isCancelled : () -> Boolean
181
179
) : Comparable<TestDispatchEvent<*>>, ThreadSafeHeapNode {
182
180
override var heap: ThreadSafeHeap <* >? = null
183
181
override var index: Int = 0
184
182
185
- override fun compareTo (other : TestDispatchEvent <* >) = if (time == other.time) {
186
- count.compareTo(other.count)
187
- } else {
188
- time.compareTo(other.time)
189
- }
183
+ override fun compareTo (other : TestDispatchEvent <* >) =
184
+ compareValuesBy(this , other, TestDispatchEvent <* >::time, TestDispatchEvent <* >::count)
190
185
191
186
override fun toString () = " TestDispatchEvent(time=$time , dispatcher=$dispatcher )"
192
187
}
0 commit comments