@@ -10,9 +10,9 @@ abstract class MainDispatcherTestBase: TestBase() {
10
10
11
11
open fun shouldSkipTesting (): Boolean = false
12
12
13
- open fun checkIsMainThread () {}
13
+ abstract fun isMainThread (): Boolean?
14
14
15
- open fun checkNotMainThread () {}
15
+ abstract fun scheduleOnMainQueue ( block : () -> Unit )
16
16
17
17
/* * Runs the given block as a test, unless [shouldSkipTesting] indicates that the environment is not suitable. */
18
18
fun runTestOrSkip (block : suspend CoroutineScope .() -> Unit ): TestResult {
@@ -57,14 +57,18 @@ abstract class MainDispatcherTestBase: TestBase() {
57
57
@Ignore // TODO: hangs on Android
58
58
fun testDelay () = runTestOrSkip {
59
59
expect(1 )
60
+ checkNotMainThread()
61
+ scheduleOnMainQueue { expect(2 ) }
60
62
withContext(Dispatchers .Main ) {
61
63
checkIsMainThread()
62
- expect(2 )
64
+ expect(3 )
65
+ scheduleOnMainQueue { expect(4 ) }
63
66
delay(100 )
64
67
checkIsMainThread()
65
- expect(3 )
68
+ expect(5 )
66
69
}
67
- finish(4 )
70
+ checkNotMainThread()
71
+ finish(6 )
68
72
}
69
73
70
74
/* * Tests that [Dispatchers.Main] shares its queue with [MainCoroutineDispatcher.immediate]. */
@@ -81,7 +85,120 @@ abstract class MainDispatcherTestBase: TestBase() {
81
85
}
82
86
expect(3 ) // after yield
83
87
yield () // yield back
84
- finish(5 )
88
+ expect(5 )
89
+ }
90
+ finish(6 )
91
+ }
92
+
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
+
169
+ /* * Tests that entering [MainCoroutineDispatcher.immediate] from [Dispatchers.Main] happens immediately. */
170
+ @Test
171
+ fun testEnteringImmediateFromMain () = runTestOrSkip {
172
+ withContext(Dispatchers .Main ) {
173
+ expect(1 )
174
+ val job = launch { expect(3 ) }
175
+ withContext(Dispatchers .Main .immediate) {
176
+ expect(2 )
177
+ }
178
+ job.join()
179
+ }
180
+ finish(4 )
181
+ }
182
+
183
+ /* * Tests that dispatching to [MainCoroutineDispatcher.immediate] is required from and only from dispatchers
184
+ * other than the main dispatchers and that it's always required for [Dispatchers.Main] itself. */
185
+ @Test
186
+ @Ignore // TODO: hangs on Android
187
+ 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
+ }
201
+ }
85
202
}
86
203
}
87
204
@@ -140,4 +257,7 @@ abstract class MainDispatcherTestBase: TestBase() {
140
257
}
141
258
}
142
259
}
260
+
261
+ fun checkIsMainThread () { isMainThread()?.let { check(it) } }
262
+ fun checkNotMainThread () { isMainThread()?.let { check(! it) } }
143
263
}
0 commit comments