• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package kotlinx.coroutines.test
2 
3 import kotlinx.coroutines.*
4 import kotlinx.coroutines.flow.*
5 import kotlinx.coroutines.internal.*
6 import kotlinx.coroutines.testing.*
7 import kotlin.coroutines.*
8 import kotlin.test.*
9 import kotlin.test.assertFailsWith
10 
11 /** Copy of [RunTestTest], but for [TestCoroutineScope] */
12 @Suppress("DEPRECATION", "DEPRECATION_ERROR")
13 class RunTestLegacyScopeTest {
14 
15     @Test
16     fun testWithContextDispatching() = runTestWithLegacyScope {
17         var counter = 0
18         withContext(Dispatchers.Default) {
19             counter += 1
20         }
21         assertEquals(counter, 1)
22     }
23 
24     @Test
25     fun testJoiningForkedJob() = runTestWithLegacyScope {
26         var counter = 0
27         val job = GlobalScope.launch {
28             counter += 1
29         }
30         job.join()
31         assertEquals(counter, 1)
32     }
33 
34     @Test
35     fun testSuspendCoroutine() = runTestWithLegacyScope {
36         val answer = suspendCoroutine<Int> {
37             it.resume(42)
38         }
39         assertEquals(42, answer)
40     }
41 
42     @Test
43     fun testNestedRunTestForbidden() = runTestWithLegacyScope {
44         assertFailsWith<IllegalStateException> {
45             runTest { }
46         }
47     }
48 
49     @Test
50     fun testRunTestWithZeroTimeoutWithControlledDispatches() = runTestWithLegacyScope(dispatchTimeoutMs = 0) {
51         // below is some arbitrary concurrent code where all dispatches go through the same scheduler.
52         launch {
53             delay(2000)
54         }
55         val deferred = async {
56             val job = launch(StandardTestDispatcher(testScheduler)) {
57                 launch {
58                     delay(500)
59                 }
60                 delay(1000)
61             }
62             job.join()
63         }
64         deferred.await()
65     }
66 
67     @Test
68     fun testRunTestWithSmallTimeout() = testResultMap({ fn ->
69         assertFailsWith<UncompletedCoroutinesError> { fn() }
70     }) {
71         runTestWithLegacyScope(dispatchTimeoutMs = 100) {
72             withContext(Dispatchers.Default) {
73                 delay(10000)
74                 3
75             }
76             fail("shouldn't be reached")
77         }
78     }
79 
80     @Test
81     fun testRunTestWithLargeTimeout() = runTestWithLegacyScope(dispatchTimeoutMs = 5000) {
82         withContext(Dispatchers.Default) {
83             delay(50)
84         }
85     }
86 
87     @Test
88     fun testRunTestTimingOutAndThrowing() = testResultMap({ fn ->
89         try {
90             fn()
91             fail("unreached")
92         } catch (e: UncompletedCoroutinesError) {
93             @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") // do not remove the INVISIBLE_REFERENCE suppression: required in K2
94             val suppressed = unwrap(e).suppressedExceptions
95             assertEquals(1, suppressed.size)
96             assertIs<TestException>(suppressed[0]).also {
97                 assertEquals("A", it.message)
98             }
99         }
100     }) {
101         runTestWithLegacyScope(dispatchTimeoutMs = 1) {
102             coroutineContext[CoroutineExceptionHandler]!!.handleException(coroutineContext, TestException("A"))
103             withContext(Dispatchers.Default) {
104                 delay(10000)
105                 3
106             }
107             fail("shouldn't be reached")
108         }
109     }
110 
111     @Test
112     fun testRunTestWithIllegalContext() {
113         for (ctx in TestScopeTest.invalidContexts) {
114             assertFailsWith<IllegalArgumentException> {
115                 runTestWithLegacyScope(ctx) { }
116             }
117         }
118     }
119 
120     @Test
121     fun testThrowingInRunTestBody() = testResultMap({
122         assertFailsWith<RuntimeException> { it() }
123     }) {
124         runTestWithLegacyScope {
125             throw RuntimeException()
126         }
127     }
128 
129     @Test
130     fun testThrowingInRunTestPendingTask() = testResultMap({
131         assertFailsWith<RuntimeException> { it() }
132     }) {
133         runTestWithLegacyScope {
134             launch {
135                 delay(SLOW)
136                 throw RuntimeException()
137             }
138         }
139     }
140 
141     @Test
142     fun reproducer2405() = runTestWithLegacyScope {
143         val dispatcher = StandardTestDispatcher(testScheduler)
144         var collectedError = false
145         withContext(dispatcher) {
146             flow { emit(1) }
147                 .combine(
148                     flow<String> { throw IllegalArgumentException() }
149                 ) { int, string -> int.toString() + string }
150                 .catch { emit("error") }
151                 .collect {
152                     assertEquals("error", it)
153                     collectedError = true
154                 }
155         }
156         assertTrue(collectedError)
157     }
158 
159     @Test
160     fun testChildrenCancellationOnTestBodyFailure(): TestResult {
161         var job: Job? = null
162         return testResultMap({
163             assertFailsWith<AssertionError> { it() }
164             assertTrue(job!!.isCancelled)
165         }) {
166             runTestWithLegacyScope {
167                 job = launch {
168                     while (true) {
169                         delay(1000)
170                     }
171                 }
172                 throw AssertionError()
173             }
174         }
175     }
176 
177     @Test
178     fun testTimeout() = testResultMap({
179         assertFailsWith<TimeoutCancellationException> { it() }
180     }) {
181         runTestWithLegacyScope {
182             withTimeout(50) {
183                 launch {
184                     delay(1000)
185                 }
186             }
187         }
188     }
189 
190     @Test
191     fun testRunTestThrowsRootCause() = testResultMap({
192         assertFailsWith<TestException> { it() }
193     }) {
194         runTestWithLegacyScope {
195             launch {
196                 throw TestException()
197             }
198         }
199     }
200 
201     @Test
202     fun testCompletesOwnJob(): TestResult {
203         var handlerCalled = false
204         return testResultMap({
205             it()
206             assertTrue(handlerCalled)
207         }) {
208             runTestWithLegacyScope {
209                 coroutineContext.job.invokeOnCompletion {
210                     handlerCalled = true
211                 }
212             }
213         }
214     }
215 
216     @Test
217     fun testDoesNotCompleteGivenJob(): TestResult {
218         var handlerCalled = false
219         val job = Job()
220         job.invokeOnCompletion {
221             handlerCalled = true
222         }
223         return testResultMap({
224             it()
225             assertFalse(handlerCalled)
226             assertEquals(0, job.children.filter { it.isActive }.count())
227         }) {
228             runTestWithLegacyScope(job) {
229                 assertTrue(coroutineContext.job in job.children)
230             }
231         }
232     }
233 
234     @Test
235     fun testSuppressedExceptions() = testResultMap({
236         try {
237             it()
238             fail("should not be reached")
239         } catch (e: TestException) {
240             assertEquals("w", e.message)
241             val suppressed = e.suppressedExceptions +
242                 (e.suppressedExceptions.firstOrNull()?.suppressedExceptions ?: emptyList())
243             assertEquals(3, suppressed.size)
244             assertEquals("x", suppressed[0].message)
245             assertEquals("y", suppressed[1].message)
246             assertEquals("z", suppressed[2].message)
247         }
248     }) {
249         runTestWithLegacyScope {
250             launch(SupervisorJob()) { throw TestException("x") }
251             launch(SupervisorJob()) { throw TestException("y") }
252             launch(SupervisorJob()) { throw TestException("z") }
253             throw TestException("w")
254         }
255     }
256 
257     @Test
258     fun testScopeRunTestExceptionHandler(): TestResult {
259         val scope = TestCoroutineScope()
260         return testResultMap({
261             try {
262                 it()
263                 fail("should not be reached")
264             } catch (e: TestException) {
265                 // expected
266             }
267         }) {
268             scope.runTest {
269                 launch(SupervisorJob()) { throw TestException("x") }
270             }
271         }
272     }
273 }
274