blob: 30a99ca02216241d5620a04a07dcd0936adb98fe [file] [log] [blame]
Denis Zharkovb8fc3432016-07-07 10:57:33 +03001package kotlinx.coroutines
Denis Zharkov8e4e0e42016-06-22 18:27:19 +03002
Roman Elizarov3754f952017-01-18 20:47:54 +03003import kotlinx.coroutines.experimental.CoroutineDispatcher
4import kotlinx.coroutines.experimental.future.await
5import kotlinx.coroutines.experimental.future.future
Denis Zharkov8e4e0e42016-06-22 18:27:19 +03006import org.junit.Test
7import java.util.concurrent.CompletableFuture
8import java.util.concurrent.ExecutionException
9import java.util.concurrent.atomic.AtomicInteger
Roman Elizarov67891d82017-01-23 16:47:20 +030010import kotlin.coroutines.CoroutineContext
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030011import kotlin.test.assertEquals
12import kotlin.test.assertFalse
13import kotlin.test.assertTrue
14import kotlin.test.fail
15
Roman Elizarov3754f952017-01-18 20:47:54 +030016class FutureTest {
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030017 @Test
18 fun testSimple() {
Roman Elizarov3754f952017-01-18 20:47:54 +030019 val future = future {
Denis Zharkovb4833122016-12-15 11:49:03 +030020 CompletableFuture.supplyAsync {
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030021 "O"
Denis Zharkovb4833122016-12-15 11:49:03 +030022 }.await() + "K"
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030023 }
24
25 assertEquals("OK", future.get())
26 }
27
28 @Test
29 fun testWaitForCompletion() {
30 val toAwait = CompletableFuture<String>()
Roman Elizarov3754f952017-01-18 20:47:54 +030031 val future = future {
Denis Zharkovb4833122016-12-15 11:49:03 +030032 toAwait.await() + "K"
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030033 }
34
35 assertFalse(future.isDone)
36 toAwait.complete("O")
37
38 assertEquals("OK", future.get())
39 }
40
41 @Test
Roman Elizarovee893442017-01-19 14:56:21 +030042 fun testDoneFutureCompletedExceptionally() {
43 val toAwait = CompletableFuture<String>()
44 toAwait.completeExceptionally(RuntimeException("O"))
45 val future = future<String> {
46 try {
47 toAwait.await()
48 } catch (e: RuntimeException) {
49 e.message!!
50 } + "K"
51 }
52
53 assertFalse(future.isDone)
54 assertEquals("OK", future.get())
55 }
56
57 @Test
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030058 fun testAwaitedFutureCompletedExceptionally() {
59 val toAwait = CompletableFuture<String>()
Roman Elizarov3754f952017-01-18 20:47:54 +030060 val future = future<String> {
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030061 try {
Denis Zharkovb4833122016-12-15 11:49:03 +030062 toAwait.await()
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030063 } catch (e: RuntimeException) {
64 e.message!!
65 } + "K"
66 }
67
68 assertFalse(future.isDone)
69 toAwait.completeExceptionally(RuntimeException("O"))
70
71 assertEquals("OK", future.get())
72 }
73
74 @Test
75 fun testExceptionInsideCoroutine() {
Roman Elizarov3754f952017-01-18 20:47:54 +030076 val future = future {
Denis Zharkovb4833122016-12-15 11:49:03 +030077 if (CompletableFuture.supplyAsync { true }.await()) {
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030078 throw IllegalStateException("OK")
79 }
Denis Zharkovb4833122016-12-15 11:49:03 +030080 CompletableFuture.supplyAsync { "fail" }.await()
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030081 }
82
83 try {
84 future.get()
85 fail("'get' should've throw an exception")
86 } catch (e: ExecutionException) {
87 assertTrue(e.cause is IllegalStateException)
88 assertEquals("OK", e.cause!!.message)
89 }
90 }
91
92 @Test
93 fun testContinuationWrapped() {
94 val depth = AtomicInteger()
95
Roman Elizarov3754f952017-01-18 20:47:54 +030096 val future = future(wrapContinuation {
Denis Zharkov8e4e0e42016-06-22 18:27:19 +030097 depth.andIncrement
98 it()
99 depth.andDecrement
100 }) {
Denis Zharkov6304ef72016-11-29 18:06:42 +0300101 assertEquals(1, depth.get(), "Part before first suspension must be wrapped")
Denis Zharkov8e4e0e42016-06-22 18:27:19 +0300102
103 val result =
Denis Zharkovb4833122016-12-15 11:49:03 +0300104 CompletableFuture.supplyAsync {
Denis Zharkov8e4e0e42016-06-22 18:27:19 +0300105 while (depth.get() > 0);
106
107 assertEquals(0, depth.get(), "Part inside suspension point should not be wrapped")
108 "OK"
Denis Zharkovb4833122016-12-15 11:49:03 +0300109 }.await()
Denis Zharkov8e4e0e42016-06-22 18:27:19 +0300110
111 assertEquals(1, depth.get(), "Part after first suspension should be wrapped")
112
Denis Zharkovb4833122016-12-15 11:49:03 +0300113 CompletableFuture.supplyAsync {
Denis Zharkov8e4e0e42016-06-22 18:27:19 +0300114 while (depth.get() > 0);
115
116 assertEquals(0, depth.get(), "Part inside suspension point should not be wrapped")
117 "ignored"
Denis Zharkovb4833122016-12-15 11:49:03 +0300118 }.await()
Denis Zharkov8e4e0e42016-06-22 18:27:19 +0300119
120 result
121 }
122
123 assertEquals("OK", future.get())
124 }
Roman Elizarov3754f952017-01-18 20:47:54 +0300125
126 private fun wrapContinuation(wrapper: (() -> Unit) -> Unit): CoroutineDispatcher = object : CoroutineDispatcher() {
Roman Elizarov67891d82017-01-23 16:47:20 +0300127 override fun isDispatchNeeded(context: CoroutineContext): Boolean = true
128 override fun dispatch(context: CoroutineContext, block: Runnable) {
Roman Elizarov3754f952017-01-18 20:47:54 +0300129 wrapper {
130 block.run()
131 }
132 }
133 }
Denis Zharkov8e4e0e42016-06-22 18:27:19 +0300134}