<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