Skip to content

Commit b25512f

Browse files
committed
Fix the ignored tests
1 parent b8fac16 commit b25512f

File tree

6 files changed

+131
-115
lines changed

6 files changed

+131
-115
lines changed

kotlinx-coroutines-core/common/test/MainDispatcherTestBase.kt

+113-110
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ abstract class MainDispatcherTestBase: TestBase() {
1010

1111
open fun shouldSkipTesting(): Boolean = false
1212

13+
open suspend fun spinTest(testBody: Job) {
14+
testBody.join()
15+
}
16+
1317
abstract fun isMainThread(): Boolean?
1418

1519
abstract fun scheduleOnMainQueue(block: () -> Unit)
@@ -19,7 +23,10 @@ abstract class MainDispatcherTestBase: TestBase() {
1923
// written as a block body to make the need to return `TestResult` explicit
2024
return runTest {
2125
if (shouldSkipTesting()) return@runTest
22-
block()
26+
val testBody = launch(Dispatchers.Default) {
27+
block()
28+
}
29+
spinTest(testBody)
2330
}
2431
}
2532

@@ -52,25 +59,6 @@ abstract class MainDispatcherTestBase: TestBase() {
5259
assertNotEquals(Dispatchers.Main, Dispatchers.Main.immediate)
5360
}
5461

55-
/** Tests that after a delay, the execution gets back to the main thread. */
56-
@Test
57-
@Ignore // TODO: hangs on Android
58-
fun testDelay() = runTestOrSkip {
59-
expect(1)
60-
checkNotMainThread()
61-
scheduleOnMainQueue { expect(2) }
62-
withContext(Dispatchers.Main) {
63-
checkIsMainThread()
64-
expect(3)
65-
scheduleOnMainQueue { expect(4) }
66-
delay(100)
67-
checkIsMainThread()
68-
expect(5)
69-
}
70-
checkNotMainThread()
71-
finish(6)
72-
}
73-
7462
/** Tests that [Dispatchers.Main] shares its queue with [MainCoroutineDispatcher.immediate]. */
7563
@Test
7664
fun testImmediateDispatcherYield() = runTestOrSkip {
@@ -90,82 +78,6 @@ abstract class MainDispatcherTestBase: TestBase() {
9078
finish(6)
9179
}
9280

93-
/** Tests that [Dispatchers.Main] is in agreement with the default time source: it's not much slower. */
94-
@Test
95-
@Ignore // TODO: hangs on Android
96-
fun testWithTimeoutContextDelayNoTimeout() = runTestOrSkip {
97-
expect(1)
98-
withTimeout(1000) {
99-
withContext(Dispatchers.Main) {
100-
checkIsMainThread()
101-
expect(2)
102-
delay(100)
103-
checkIsMainThread()
104-
expect(3)
105-
}
106-
}
107-
checkNotMainThread()
108-
finish(4)
109-
}
110-
111-
/** Tests that [Dispatchers.Main] is in agreement with the default time source: it's not much faster. */
112-
@Test
113-
@Ignore // TODO: hangs on Android
114-
fun testWithTimeoutContextDelayTimeout() = runTestOrSkip {
115-
expect(1)
116-
assertFailsWith<TimeoutCancellationException> {
117-
withTimeout(300) {
118-
withContext(Dispatchers.Main) {
119-
checkIsMainThread()
120-
expect(2)
121-
delay(1000)
122-
expectUnreached()
123-
}
124-
}
125-
expectUnreached()
126-
}
127-
checkNotMainThread()
128-
finish(3)
129-
}
130-
131-
/** Tests that the timeout of [Dispatchers.Main] is in agreement with its [delay]: it's not much faster. */
132-
@Test
133-
@Ignore // TODO: hangs on Android
134-
fun testWithContextTimeoutDelayNoTimeout() = runTestOrSkip {
135-
expect(1)
136-
withContext(Dispatchers.Main) {
137-
withTimeout(1000) {
138-
checkIsMainThread()
139-
expect(2)
140-
delay(100)
141-
checkIsMainThread()
142-
expect(3)
143-
}
144-
}
145-
checkNotMainThread()
146-
finish(4)
147-
}
148-
149-
/** Tests that the timeout of [Dispatchers.Main] is in agreement with its [delay]: it's not much slower. */
150-
@Test
151-
@Ignore // TODO: hangs on Android
152-
fun testWithContextTimeoutDelayTimeout() = runTestOrSkip {
153-
expect(1)
154-
assertFailsWith<TimeoutCancellationException> {
155-
withContext(Dispatchers.Main) {
156-
withTimeout(100) {
157-
checkIsMainThread()
158-
expect(2)
159-
delay(1000)
160-
expectUnreached()
161-
}
162-
}
163-
expectUnreached()
164-
}
165-
checkNotMainThread()
166-
finish(3)
167-
}
168-
16981
/** Tests that entering [MainCoroutineDispatcher.immediate] from [Dispatchers.Main] happens immediately. */
17082
@Test
17183
fun testEnteringImmediateFromMain() = runTestOrSkip {
@@ -183,23 +95,22 @@ abstract class MainDispatcherTestBase: TestBase() {
18395
/** Tests that dispatching to [MainCoroutineDispatcher.immediate] is required from and only from dispatchers
18496
* other than the main dispatchers and that it's always required for [Dispatchers.Main] itself. */
18597
@Test
186-
@Ignore // TODO: hangs on Android
18798
fun testDispatchRequirements() = runTestOrSkip {
188-
withContext(Dispatchers.Default) {
189-
assertTrue(Dispatchers.Main.immediate.isDispatchNeeded(currentCoroutineContext()))
190-
assertTrue(Dispatchers.Main.isDispatchNeeded(currentCoroutineContext()))
191-
assertTrue(Dispatchers.Default.isDispatchNeeded(currentCoroutineContext()))
192-
withContext(Dispatchers.Main) {
193-
assertFalse(Dispatchers.Main.immediate.isDispatchNeeded(currentCoroutineContext()))
194-
assertTrue(Dispatchers.Main.isDispatchNeeded(currentCoroutineContext()))
195-
assertTrue(Dispatchers.Default.isDispatchNeeded(currentCoroutineContext()))
196-
withContext(Dispatchers.Main.immediate) {
197-
assertFalse(Dispatchers.Main.immediate.isDispatchNeeded(currentCoroutineContext()))
198-
assertTrue(Dispatchers.Main.isDispatchNeeded(currentCoroutineContext()))
199-
assertTrue(Dispatchers.Default.isDispatchNeeded(currentCoroutineContext()))
200-
}
99+
checkDispatchRequirements()
100+
withContext(Dispatchers.Main) {
101+
checkDispatchRequirements()
102+
withContext(Dispatchers.Main.immediate) {
103+
checkDispatchRequirements()
201104
}
105+
checkDispatchRequirements()
202106
}
107+
checkDispatchRequirements()
108+
}
109+
110+
private suspend fun checkDispatchRequirements() {
111+
isMainThread()?.let { assertNotEquals(it, Dispatchers.Main.immediate.isDispatchNeeded(currentCoroutineContext())) }
112+
assertTrue(Dispatchers.Main.isDispatchNeeded(currentCoroutineContext()))
113+
assertTrue(Dispatchers.Default.isDispatchNeeded(currentCoroutineContext()))
203114
}
204115

205116
/** Tests that launching a coroutine in [MainScope] will execute it in the main thread. */
@@ -258,6 +169,98 @@ abstract class MainDispatcherTestBase: TestBase() {
258169
}
259170
}
260171

172+
abstract class WithRealTimeDelay : MainDispatcherTestBase() {
173+
/** Tests that after a delay, the execution gets back to the main thread. */
174+
@Test
175+
fun testDelay() = runTestOrSkip {
176+
expect(1)
177+
checkNotMainThread()
178+
scheduleOnMainQueue { expect(2) }
179+
withContext(Dispatchers.Main) {
180+
checkIsMainThread()
181+
expect(3)
182+
scheduleOnMainQueue { expect(4) }
183+
delay(100)
184+
checkIsMainThread()
185+
expect(5)
186+
}
187+
checkNotMainThread()
188+
finish(6)
189+
}
190+
191+
/** Tests that [Dispatchers.Main] is in agreement with the default time source: it's not much slower. */
192+
@Test
193+
fun testWithTimeoutContextDelayNoTimeout() = runTestOrSkip {
194+
expect(1)
195+
withTimeout(1000) {
196+
withContext(Dispatchers.Main) {
197+
checkIsMainThread()
198+
expect(2)
199+
delay(100)
200+
checkIsMainThread()
201+
expect(3)
202+
}
203+
}
204+
checkNotMainThread()
205+
finish(4)
206+
}
207+
208+
/** Tests that [Dispatchers.Main] is in agreement with the default time source: it's not much faster. */
209+
@Test
210+
fun testWithTimeoutContextDelayTimeout() = runTestOrSkip {
211+
expect(1)
212+
assertFailsWith<TimeoutCancellationException> {
213+
withTimeout(300) {
214+
withContext(Dispatchers.Main) {
215+
checkIsMainThread()
216+
expect(2)
217+
delay(1000)
218+
expectUnreached()
219+
}
220+
}
221+
expectUnreached()
222+
}
223+
checkNotMainThread()
224+
finish(3)
225+
}
226+
227+
/** Tests that the timeout of [Dispatchers.Main] is in agreement with its [delay]: it's not much faster. */
228+
@Test
229+
fun testWithContextTimeoutDelayNoTimeout() = runTestOrSkip {
230+
expect(1)
231+
withContext(Dispatchers.Main) {
232+
withTimeout(1000) {
233+
checkIsMainThread()
234+
expect(2)
235+
delay(100)
236+
checkIsMainThread()
237+
expect(3)
238+
}
239+
}
240+
checkNotMainThread()
241+
finish(4)
242+
}
243+
244+
/** Tests that the timeout of [Dispatchers.Main] is in agreement with its [delay]: it's not much slower. */
245+
@Test
246+
fun testWithContextTimeoutDelayTimeout() = runTestOrSkip {
247+
expect(1)
248+
assertFailsWith<TimeoutCancellationException> {
249+
withContext(Dispatchers.Main) {
250+
withTimeout(100) {
251+
checkIsMainThread()
252+
expect(2)
253+
delay(1000)
254+
expectUnreached()
255+
}
256+
}
257+
expectUnreached()
258+
}
259+
checkNotMainThread()
260+
finish(3)
261+
}
262+
}
263+
261264
fun checkIsMainThread() { isMainThread()?.let { check(it) } }
262265
fun checkNotMainThread() { isMainThread()?.let { check(!it) } }
263266
}

kotlinx-coroutines-core/js/test/ImmediateDispatcherTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package kotlinx.coroutines
77
import kotlin.coroutines.*
88
import kotlin.test.*
99

10-
class ImmediateDispatcherTest : MainDispatcherTestBase() {
10+
class ImmediateDispatcherTest : MainDispatcherTestBase.WithRealTimeDelay() {
1111

1212
/** Tests that [MainCoroutineDispatcher.immediate] doesn't require dispatches from the test context. */
1313
@Test

kotlinx-coroutines-core/nativeDarwin/test/MainDispatcherTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import platform.darwin.*
99
import kotlin.coroutines.*
1010
import kotlin.test.*
1111

12-
class MainDispatcherTest : MainDispatcherTestBase() {
12+
class MainDispatcherTest : MainDispatcherTestBase.WithRealTimeDelay() {
1313

1414
override fun isMainThread(): Boolean = CFRunLoopGetCurrent() == CFRunLoopGetMain()
1515

ui/kotlinx-coroutines-android/test/HandlerDispatcherTest.kt

+14-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ import org.robolectric.annotation.*
1313
import org.robolectric.shadows.*
1414
import java.util.concurrent.*
1515
import kotlin.test.*
16+
import kotlin.time.*
17+
import kotlin.time.Duration.Companion.milliseconds
18+
import kotlin.time.Duration.Companion.seconds
1619

1720
@RunWith(RobolectricTestRunner::class)
1821
@LooperMode(LooperMode.Mode.LEGACY)
1922
@Config(manifest = Config.NONE, sdk = [28])
20-
class HandlerDispatcherTest : MainDispatcherTestBase() {
23+
class HandlerDispatcherTest : MainDispatcherTestBase.WithRealTimeDelay() {
2124
@Test
2225
fun testDefaultDelayIsNotDelegatedToMain() = runTest {
2326
val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
@@ -118,4 +121,14 @@ class HandlerDispatcherTest : MainDispatcherTestBase() {
118121
override fun scheduleOnMainQueue(block: () -> Unit) {
119122
Handler(Looper.getMainLooper()).post(block)
120123
}
124+
125+
// by default, Robolectric only schedules tasks on the main thread but doesn't run them.
126+
// This function nudges it to run them, 10 milliseconds of virtual time at a time.
127+
override suspend fun spinTest(testBody: Job) {
128+
val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
129+
while (testBody.isActive) {
130+
Thread.sleep(10, 0)
131+
mainLooper.idleFor(10, TimeUnit.MILLISECONDS)
132+
}
133+
}
121134
}

ui/kotlinx-coroutines-javafx/test/JavaFxDispatcherTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import org.junit.Test
1111
import javax.swing.*
1212
import kotlin.test.*
1313

14-
class JavaFxDispatcherTest : MainDispatcherTestBase() {
14+
class JavaFxDispatcherTest : MainDispatcherTestBase.WithRealTimeDelay() {
1515
@Before
1616
fun setup() {
1717
ignoreLostThreads("JavaFX Application Thread", "Thread-", "QuantumRenderer-", "InvokeLaterDispatcher")

ui/kotlinx-coroutines-swing/test/SwingTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import javax.swing.*
1111
import kotlin.coroutines.*
1212
import kotlin.test.*
1313

14-
class SwingTest : MainDispatcherTestBase() {
14+
class SwingTest : MainDispatcherTestBase.WithRealTimeDelay() {
1515
@Before
1616
fun setup() {
1717
ignoreLostThreads("AWT-EventQueue-")

0 commit comments

Comments
 (0)