/* * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ @file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED", "DEPRECATION") // KT-21913 package kotlinx.coroutines import kotlin.test.* class CompletableDeferredTest : TestBase() { @Test fun testFresh() { val c = CompletableDeferred() checkFresh(c) } @Test fun testComplete() { val c = CompletableDeferred() assertEquals(true, c.complete("OK")) checkCompleteOk(c) assertEquals("OK", c.getCompleted()) assertEquals(false, c.complete("OK")) checkCompleteOk(c) assertEquals("OK", c.getCompleted()) } @Test fun testCompleteWithIncompleteResult() { val c = CompletableDeferred() assertEquals(true, c.complete(c.invokeOnCompletion { })) checkCompleteOk(c) assertEquals(false, c.complete(c.invokeOnCompletion { })) checkCompleteOk(c) assertTrue(c.getCompleted() is Incomplete) } private fun checkFresh(c: CompletableDeferred<*>) { assertEquals(true, c.isActive) assertEquals(false, c.isCancelled) assertEquals(false, c.isCompleted) assertThrows { c.getCancellationException() } assertThrows { c.getCompleted() } assertThrows { c.getCompletionExceptionOrNull() } } private fun checkCompleteOk(c: CompletableDeferred<*>) { assertEquals(false, c.isActive) assertEquals(false, c.isCancelled) assertEquals(true, c.isCompleted) assertTrue(c.getCancellationException() is JobCancellationException) assertEquals(null, c.getCompletionExceptionOrNull()) } private fun checkCancel(c: CompletableDeferred) { assertEquals(false, c.isActive) assertEquals(true, c.isCancelled) assertEquals(true, c.isCompleted) assertThrows { c.getCompleted() } assertTrue(c.getCompletionExceptionOrNull() is CancellationException) } @Test fun testCancelWithException() { val c = CompletableDeferred() assertEquals(true, c.completeExceptionally(TestException())) checkCancelWithException(c) assertEquals(false, c.completeExceptionally(TestException())) checkCancelWithException(c) } private fun checkCancelWithException(c: CompletableDeferred) { assertEquals(false, c.isActive) assertEquals(true, c.isCancelled) assertEquals(true, c.isCompleted) assertTrue(c.getCancellationException() is JobCancellationException) assertThrows { c.getCompleted() } assertTrue(c.getCompletionExceptionOrNull() is TestException) } @Test fun testParentCancelsChild() { val parent = Job() val c = CompletableDeferred(parent) checkFresh(c) parent.cancel() assertEquals(false, parent.isActive) assertEquals(true, parent.isCancelled) assertEquals(false, c.isActive) assertEquals(true, c.isCancelled) assertEquals(true, c.isCompleted) assertThrows { c.getCompleted() } assertTrue(c.getCompletionExceptionOrNull() is CancellationException) } @Test fun testParentActiveOnChildCompletion() { val parent = Job() val c = CompletableDeferred(parent) checkFresh(c) assertEquals(true, parent.isActive) assertEquals(true, c.complete("OK")) checkCompleteOk(c) assertEquals(true, parent.isActive) } @Test fun testParentCancelledOnChildException() { val parent = Job() val c = CompletableDeferred(parent) checkFresh(c) assertEquals(true, parent.isActive) assertEquals(true, c.completeExceptionally(TestException())) checkCancelWithException(c) assertEquals(false, parent.isActive) assertEquals(true, parent.isCancelled) } @Test fun testParentActiveOnChildCancellation() { val parent = Job() val c = CompletableDeferred(parent) checkFresh(c) assertEquals(true, parent.isActive) c.cancel() checkCancel(c) assertEquals(true, parent.isActive) } @Test fun testAwait() = runTest { expect(1) val c = CompletableDeferred() launch(start = CoroutineStart.UNDISPATCHED) { expect(2) assertEquals("OK", c.await()) // suspends expect(5) assertEquals("OK", c.await()) // does not suspend expect(6) } expect(3) c.complete("OK") expect(4) yield() // to launch finish(7) } @Test fun testCancelAndAwaitParentWaitChildren() = runTest { expect(1) val parent = CompletableDeferred() launch(parent, start = CoroutineStart.UNDISPATCHED) { expect(2) try { yield() // will get cancelled } finally { expect(5) } } expect(3) parent.cancel() expect(4) try { parent.await() } catch (e: CancellationException) { finish(6) } } @Test fun testCompleteAndAwaitParentWaitChildren() = runTest { expect(1) val parent = CompletableDeferred() launch(parent, start = CoroutineStart.UNDISPATCHED) { expect(2) try { yield() // will get cancelled } finally { expect(5) } } expect(3) parent.complete("OK") expect(4) assertEquals("OK", parent.await()) finish(6) } private inline fun assertThrows(block: () -> Unit) { try { block() fail("Should not complete normally") } catch (e: Throwable) { assertTrue(e is T) } } }