Skip to content

Commit e2e2d10

Browse files
committed
Fixes
1 parent 25a7fe0 commit e2e2d10

6 files changed

+35
-40
lines changed

kotlinx-coroutines-test/common/src/DelayController.kt

+11-11
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
1212
*
1313
* Testing libraries may expose this interface to the tests instead of [TestCoroutineDispatcher].
1414
*/
15-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
15+
@ExperimentalCoroutinesApi
1616
@Deprecated("Use `TestCoroutineScheduler` to control virtual time.",
1717
level = DeprecationLevel.WARNING)
1818
public interface DelayController {
@@ -21,7 +21,7 @@ public interface DelayController {
2121
*
2222
* @return The virtual clock-time
2323
*/
24-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
24+
@ExperimentalCoroutinesApi
2525
public val currentTime: Long
2626

2727
/**
@@ -59,7 +59,7 @@ public interface DelayController {
5959
* @param delayTimeMillis The amount of time to move the CoroutineContext's clock forward.
6060
* @return The amount of delay-time that this Dispatcher's clock has been forwarded.
6161
*/
62-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
62+
@ExperimentalCoroutinesApi
6363
public fun advanceTimeBy(delayTimeMillis: Long): Long
6464

6565
/**
@@ -70,15 +70,15 @@ public interface DelayController {
7070
*
7171
* @return the amount of delay-time that this Dispatcher's clock has been forwarded in milliseconds.
7272
*/
73-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
73+
@ExperimentalCoroutinesApi
7474
public fun advanceUntilIdle(): Long
7575

7676
/**
7777
* Run any tasks that are pending at or before the current virtual clock-time.
7878
*
7979
* Calling this function will never advance the clock.
8080
*/
81-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
81+
@ExperimentalCoroutinesApi
8282
public fun runCurrent()
8383

8484
/**
@@ -87,7 +87,7 @@ public interface DelayController {
8787
* @throws UncompletedCoroutinesError if any pending tasks are active, however it will not throw for suspended
8888
* coroutines.
8989
*/
90-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
90+
@ExperimentalCoroutinesApi
9191
@Throws(UncompletedCoroutinesError::class)
9292
public fun cleanupTestCoroutines()
9393

@@ -100,7 +100,7 @@ public interface DelayController {
100100
* This is useful when testing functions that start a coroutine. By pausing the dispatcher assertions or
101101
* setup may be done between the time the coroutine is created and started.
102102
*/
103-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
103+
@ExperimentalCoroutinesApi
104104
public suspend fun pauseDispatcher(block: suspend () -> Unit)
105105

106106
/**
@@ -109,7 +109,7 @@ public interface DelayController {
109109
* When paused, the dispatcher will not execute any coroutines automatically, and you must call [runCurrent] or
110110
* [advanceTimeBy], or [advanceUntilIdle] to execute coroutines.
111111
*/
112-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
112+
@ExperimentalCoroutinesApi
113113
public fun pauseDispatcher()
114114

115115
/**
@@ -119,15 +119,15 @@ public interface DelayController {
119119
* time and execute coroutines scheduled in the future use, one of [advanceTimeBy],
120120
* or [advanceUntilIdle].
121121
*/
122-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
122+
@ExperimentalCoroutinesApi
123123
public fun resumeDispatcher()
124124
}
125125

126126
/**
127127
* Thrown when a test has completed and there are tasks that are not completed or cancelled.
128128
*/
129129
// todo: maybe convert into non-public class in 1.3.0 (need use-cases for a public exception type)
130-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
130+
@ExperimentalCoroutinesApi
131131
public class UncompletedCoroutinesError(message: String): AssertionError(message)
132132

133133
internal interface SchedulerAsDelayController: DelayController {
@@ -179,4 +179,4 @@ internal interface SchedulerAsDelayController: DelayController {
179179
)
180180
}
181181
}
182-
}
182+
}

kotlinx-coroutines-test/common/src/TestBuilders.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import kotlin.coroutines.*
4141
* then they must implement [DelayController] and [TestCoroutineExceptionHandler] respectively.
4242
* @param testBody The code of the unit-test.
4343
*/
44-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
44+
@ExperimentalCoroutinesApi
4545
public fun runBlockingTest(context: CoroutineContext = EmptyCoroutineContext, testBody: suspend TestCoroutineScope.() -> Unit) {
4646
val (safeContext, dispatcher) = context.checkTestScopeArguments()
4747
val startingJobs = safeContext.activeJobs()
@@ -68,14 +68,14 @@ private fun CoroutineContext.activeJobs(): Set<Job> {
6868
* Convenience method for calling [runBlockingTest] on an existing [TestCoroutineScope].
6969
*/
7070
// todo: need documentation on how this extension is supposed to be used
71-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
71+
@ExperimentalCoroutinesApi
7272
public fun TestCoroutineScope.runBlockingTest(block: suspend TestCoroutineScope.() -> Unit): Unit =
7373
runBlockingTest(coroutineContext, block)
7474

7575
/**
7676
* Convenience method for calling [runBlockingTest] on an existing [TestCoroutineDispatcher].
7777
*/
78-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
78+
@ExperimentalCoroutinesApi
7979
public fun TestCoroutineDispatcher.runBlockingTest(block: suspend TestCoroutineScope.() -> Unit): Unit =
8080
runBlockingTest(this, block)
8181

kotlinx-coroutines-test/common/src/TestCoroutineDispatcher.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import kotlin.coroutines.*
2121
*
2222
* @see DelayController
2323
*/
24-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
24+
@ExperimentalCoroutinesApi
2525
public class TestCoroutineDispatcher(public override val scheduler: TestCoroutineScheduler = TestCoroutineScheduler()):
2626
TestDispatcher(), Delay, SchedulerAsDelayController
2727
{

kotlinx-coroutines-test/common/src/TestCoroutineExceptionHandler.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import kotlin.coroutines.*
1111
/**
1212
* Access uncaught coroutine exceptions captured during test execution.
1313
*/
14-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
14+
@ExperimentalCoroutinesApi
1515
public interface UncaughtExceptionCaptor {
1616
/**
1717
* List of uncaught coroutine exceptions.
@@ -35,7 +35,7 @@ public interface UncaughtExceptionCaptor {
3535
/**
3636
* An exception handler that captures uncaught exceptions in tests.
3737
*/
38-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
38+
@ExperimentalCoroutinesApi
3939
public class TestCoroutineExceptionHandler :
4040
AbstractCoroutineContextElement(CoroutineExceptionHandler), UncaughtExceptionCaptor, CoroutineExceptionHandler
4141
{

kotlinx-coroutines-test/common/src/TestCoroutineScheduler.kt

+14-19
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import kotlin.jvm.*
1313
/**
1414
* This is a scheduler for coroutines used in tests, providing the delay-skipping behavior.
1515
*
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
1919
* the tasks.
2020
*
2121
* 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.*
2626
// TODO: maybe make this a `TimeSource`?
2727
public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCoroutineScheduler), CoroutineContext.Element {
2828

29+
/** @suppress */
2930
public companion object Key: CoroutineContext.Key<TestCoroutineScheduler>
3031

3132
/** 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
4546
private set
4647

4748
/**
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.
5051
*
5152
* Returns the handler which can be used to cancel the registration.
5253
*/
@@ -74,7 +75,7 @@ public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCorouti
7475
* Runs the enqueued tasks in the specified order, advancing the virtual time as needed until there are no more
7576
* tasks associated with the dispatchers linked to this scheduler.
7677
*
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
7879
* milliseconds by which the execution of this method has advanced the virtual time. If you want to recreate that
7980
* functionality, query [currentTime] before and after the execution to achieve the same result.
8081
*/
@@ -124,24 +125,22 @@ public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCorouti
124125
*/
125126
@ExperimentalCoroutinesApi
126127
public fun advanceTimeBy(delayTimeMillis: Long) {
127-
require(delayTimeMillis >= 0) { "" }
128+
require(delayTimeMillis >= 0) { "Can not advance time by a negative delay: $delayTimeMillis" }
128129
val startingTime = currentTime
129130
val targetTime = addClamping(startingTime, delayTimeMillis)
130131
while (true) {
131132
val event = synchronized(lock) {
132133
val timeMark = currentTime
133-
val event = events.peek()
134+
val event = events.removeFirstIf { targetTime > it.time }
134135
when {
135-
event == null || targetTime <= event.time -> {
136+
event == null -> {
136137
currentTime = targetTime
137138
return
138139
}
139140
timeMark > event.time -> currentTimeAheadOfEvents()
140141
else -> {
141-
val event2 = events.removeFirstOrNull()
142-
if (event !== event2) concurrentModificationUnderLock()
143142
currentTime = event.time
144-
event2
143+
event
145144
}
146145
}
147146
}
@@ -166,7 +165,6 @@ public class TestCoroutineScheduler: AbstractCoroutineContextElement(TestCorouti
166165

167166
// Some error-throwing functions for pretty stack traces
168167
private fun currentTimeAheadOfEvents(): Nothing = invalidSchedulerState()
169-
private fun concurrentModificationUnderLock(): Nothing = invalidSchedulerState()
170168

171169
private fun invalidSchedulerState(): Nothing =
172170
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>(
177175
private val count: Long,
178176
@JvmField val time: Long,
179177
@JvmField val marker: T,
180-
val isCancelled: () -> Boolean
178+
@JvmField val isCancelled: () -> Boolean
181179
) : Comparable<TestDispatchEvent<*>>, ThreadSafeHeapNode {
182180
override var heap: ThreadSafeHeap<*>? = null
183181
override var index: Int = 0
184182

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)
190185

191186
override fun toString() = "TestDispatchEvent(time=$time, dispatcher=$dispatcher)"
192187
}

kotlinx-coroutines-test/common/src/TestCoroutineScope.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import kotlin.coroutines.*
1010
/**
1111
* A scope which provides detailed control over the execution of coroutines for tests.
1212
*/
13-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
13+
@ExperimentalCoroutinesApi
1414
public interface TestCoroutineScope: CoroutineScope, UncaughtExceptionCaptor {
1515
/**
1616
* Call after the test completes.
@@ -54,7 +54,7 @@ private class TestCoroutineScopeImpl (
5454
* @param context an optional context that MAY provide [UncaughtExceptionCaptor] and/or [DelayController]
5555
*/
5656
@Suppress("FunctionName")
57-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
57+
@ExperimentalCoroutinesApi
5858
public fun TestCoroutineScope(context: CoroutineContext = EmptyCoroutineContext): TestCoroutineScope =
5959
context.checkTestScopeArguments().let { TestCoroutineScopeImpl(it.first, it.second.scheduler) }
6060

@@ -109,7 +109,7 @@ public fun TestCoroutineScope.advanceTimeBy(delayTimeMillis: Long): Unit =
109109
* Advances the [testScheduler][TestCoroutineScope.testScheduler] to the point where there are no tasks remaining.
110110
* @see TestCoroutineScheduler.advanceUntilIdle
111111
*/
112-
@ExperimentalCoroutinesApi // Since 1.2.1, tentatively till 1.3.0
112+
@ExperimentalCoroutinesApi
113113
public fun TestCoroutineScope.advanceUntilIdle(): Unit {
114114
coroutineContext.delayController?.advanceUntilIdle() ?: testScheduler.advanceUntilIdle()
115115
}
@@ -157,4 +157,4 @@ public fun TestCoroutineScope.resumeDispatcher() {
157157

158158
private val TestCoroutineScope.delayControllerForPausing: DelayController
159159
get() = coroutineContext.delayController
160-
?: throw IllegalStateException("This scope isn't able to pause its dispatchers")
160+
?: throw IllegalStateException("This scope isn't able to pause its dispatchers")

0 commit comments

Comments
 (0)