• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.coroutines.android
6 
7 import android.os.*
8 import kotlinx.coroutines.*
9 import org.junit.Test
10 import org.junit.runner.*
11 import org.robolectric.*
12 import org.robolectric.annotation.*
13 import org.robolectric.shadows.*
14 import java.util.concurrent.*
15 import kotlin.test.*
16 
17 @RunWith(RobolectricTestRunner::class)
18 @Config(manifest = Config.NONE, sdk = [28])
19 @LooperMode(LooperMode.Mode.LEGACY)
20 class HandlerDispatcherTest : TestBase() {
21     @Test
<lambda>null22     fun testImmediateDispatcherYield() = runBlocking(Dispatchers.Main) {
23         expect(1)
24         // launch in the immediate dispatcher
25         launch(Dispatchers.Main.immediate) {
26             expect(2)
27             yield()
28             expect(4)
29         }
30         expect(3) // after yield
31         yield() // yield back
32         finish(5)
33     }
34 
35     @Test
testMainDispatcherToStringnull36     fun testMainDispatcherToString() {
37         assertEquals("Dispatchers.Main", Dispatchers.Main.toString())
38         assertEquals("Dispatchers.Main.immediate", Dispatchers.Main.immediate.toString())
39     }
40 
41     @Test
<lambda>null42     fun testDefaultDelayIsNotDelegatedToMain() = runTest {
43         val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
44         mainLooper.pause()
45         assertFalse { mainLooper.scheduler.areAnyRunnable() }
46 
47         val job = launch(Dispatchers.Default, start = CoroutineStart.UNDISPATCHED) {
48             expect(1)
49             delay(Long.MAX_VALUE)
50             expectUnreached()
51         }
52         expect(2)
53         assertEquals(0, mainLooper.scheduler.size())
54         job.cancelAndJoin()
55         finish(3)
56     }
57 
58     @Test
<lambda>null59     fun testWithTimeoutIsDelegatedToMain() = runTest {
60         val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
61         mainLooper.pause()
62         assertFalse { mainLooper.scheduler.areAnyRunnable() }
63         val job = launch(Dispatchers.Main, start = CoroutineStart.UNDISPATCHED) {
64             withTimeout(1) {
65                 expect(1)
66                 hang { expect(3) }
67             }
68             expectUnreached()
69         }
70         expect(2)
71         assertEquals(1, mainLooper.scheduler.size())
72         // Schedule cancellation
73         mainLooper.runToEndOfTasks()
74         job.join()
75         finish(4)
76     }
77 
78     @Test
<lambda>null79     fun testDelayDelegatedToMain() = runTest {
80         val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
81         mainLooper.pause()
82         val job = launch(Dispatchers.Main, start = CoroutineStart.UNDISPATCHED) {
83             expect(1)
84             delay(1)
85             expect(3)
86         }
87         expect(2)
88         assertEquals(1, mainLooper.scheduler.size())
89         // Schedule cancellation
90         mainLooper.runToEndOfTasks()
91         job.join()
92         finish(4)
93     }
94 
95     @Test
<lambda>null96     fun testAwaitFrame() = runTest {
97         doTestAwaitFrame()
98 
99         reset()
100 
101         // Now the second test: we cannot test it separately because we're caching choreographer in HandlerDispatcher
102         doTestAwaitWithDetectedChoreographer()
103     }
104 
CoroutineScopenull105     private fun CoroutineScope.doTestAwaitFrame() {
106         ShadowChoreographer.setPostFrameCallbackDelay(100)
107         val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
108         mainLooper.pause()
109         launch(Dispatchers.Main, start = CoroutineStart.UNDISPATCHED) {
110             expect(1)
111             awaitFrame()
112             expect(5)
113         }
114         expect(2)
115         // Run choreographer detection
116         mainLooper.runOneTask()
117         expect(3)
118         mainLooper.scheduler.advanceBy(50, TimeUnit.MILLISECONDS)
119         expect(4)
120         mainLooper.scheduler.advanceBy(51, TimeUnit.MILLISECONDS)
121         finish(6)
122     }
123 
CoroutineScopenull124     private fun CoroutineScope.doTestAwaitWithDetectedChoreographer() {
125         ShadowChoreographer.setPostFrameCallbackDelay(100)
126         val mainLooper = Shadows.shadowOf(Looper.getMainLooper())
127         launch(Dispatchers.Main, start = CoroutineStart.UNDISPATCHED) {
128             expect(1)
129             awaitFrame()
130             expect(4)
131         }
132         // Run choreographer detection
133         expect(2)
134         mainLooper.scheduler.advanceBy(50, TimeUnit.MILLISECONDS)
135         expect(3)
136         mainLooper.scheduler.advanceBy(51, TimeUnit.MILLISECONDS)
137         finish(5)
138     }
139 }
140